Browse Source

Merge branch 'master' into olym

olym 8 years ago
parent
commit
23514e0159
32 changed files with 1495 additions and 90 deletions
  1. 1 1
      config/config.js
  2. 13 7
      modules/fee_rates/facade/fee_rates_facade.js
  3. 6 0
      modules/main/models/bills.js
  4. 20 1
      modules/main/models/bills_sub_schemas.js
  5. 1 0
      modules/main/models/proj_counter.js
  6. 11 10
      modules/pm/controllers/new_proj_controller.js
  7. 2 2
      modules/pm/models/project_model.js
  8. 75 0
      modules/pm/models/templates/bills_template_model.js
  9. 35 0
      modules/pm/models/templates/schemas/bills_template.js
  10. 80 13
      modules/reports/controllers/rpt_controller.js
  11. 4 0
      modules/reports/routes/report_router.js
  12. 4 1
      modules/reports/rpt_component/jpc_ex.js
  13. 230 0
      modules/reports/util/canvas_util.js
  14. BIN
      modules/reports/util/pdf_base_files/Smart-italic.ttf
  15. BIN
      modules/reports/util/pdf_base_files/Smart.ttf
  16. BIN
      modules/reports/util/pdf_base_files/hwxsb.ttf
  17. 49 0
      modules/reports/util/pdf_base_files/rpt_pdf_consts.js
  18. 59 0
      modules/reports/util/pdfkit_test.js
  19. 144 17
      modules/reports/util/rpt_excel_util.js
  20. 202 0
      modules/reports/util/rpt_pdf_util.js
  21. 2 1
      package.json
  22. 7 0
      public/fsUtil.js
  23. 3 0
      public/web/rpt_value_define.js
  24. 13 0
      public/web/tree_sheet/tree_sheet_helper.js
  25. 4 3
      test/tmp_data/bills_grid_setting.js
  26. 34 29
      web/building_saas/complementary_glj_lib/js/components.js
  27. 2 2
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  28. 16 0
      web/building_saas/main/html/main.html
  29. 426 0
      web/building_saas/main/js/views/character_content_view.js
  30. 9 1
      web/building_saas/main/js/views/main_tree_col.js
  31. 16 1
      web/building_saas/main/js/views/project_view.js
  32. 27 1
      web/building_saas/main/js/views/sub_view.js

+ 1 - 1
config/config.js

@@ -19,7 +19,7 @@ module.exports = {
             },
             },
             "server": {
             "server": {
                  "socketOptions": {
                  "socketOptions": {
-                "connectTimeoutMS": 10000
+                 "connectTimeoutMS": 10000
                 }
                 }
             }
             }
         }
         }

+ 13 - 7
modules/fee_rates/facade/fee_rates_facade.js

@@ -184,13 +184,19 @@ async function getFeeRateData(projectID) {
     }
     }
     try {
     try {
         //
         //
-        let tem = await project_feerate_temp.findOne({projectID:projectID});//暂时取tem表的记录
-        let feeRateData = await feeRateFileModel.findOne({'ID':tem.feeRateFileID,deleteInfo:null});
-        let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
-        feeRateData._doc.rates = feeRate.rates;
-        //
-        feeRateData._doc.usageProjects=getUsageProjects(feeRateData.ID);
-        result.datas = feeRateData;
+        let tem = await project_feerate_temp.findOne({projectID:projectID});//暂时取tem表的记录,写死为99
+        if (tem){
+            let feeRateData = await feeRateFileModel.findOne({'ID':tem.feeRateFileID,deleteInfo:null});
+            let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
+            feeRateData._doc.rates = feeRate.rates;
+            //
+            feeRateData._doc.usageProjects=getUsageProjects(feeRateData.ID);
+            result.datas = feeRateData;
+        }else {
+            result.datas=[];
+        }
+
+
     }catch (err){
     }catch (err){
         console.log(err);
         console.log(err);
         result.err=err;
         result.err=err;

+ 6 - 0
modules/main/models/bills.js

@@ -43,6 +43,12 @@ let billsSchema = new Schema({
     tenderTargetPrice: String, // Decimal
     tenderTargetPrice: String, // Decimal
     tenderTargetUnitPrice: String, // Decimal
     tenderTargetUnitPrice: String, // Decimal
     tenderTargetUnitPrice: String, // Decimal
     tenderTargetUnitPrice: String, // Decimal
+    //工作内容
+    jobContentText: String, //清单工作内容列显示文本, 减少第一次拉时的循环次数
+    jobContent: [subSchema.jobContentSchema],
+    //项目特征
+    itemCharacterText: String,//清单项目特征列显示文本
+    itemCharacter: [subSchema.itemCharacterSchema],
     // 费用字段
     // 费用字段
     fees: [subSchema.feesSchema],
     fees: [subSchema.feesSchema],
     // 标记字段
     // 标记字段

+ 20 - 1
modules/main/models/bills_sub_schemas.js

@@ -25,4 +25,23 @@ var changesSchema = new Schema({
     deleteGLJ:String
     deleteGLJ:String
 });
 });
 
 
-module.exports = {feesSchema: feesSchema, flagsSchema: flagsSchema};
+//add by Zhong2017-8-30
+//清单工作内容字段
+let jobContentSchema = new Schema({
+    content: String, //工作内容
+    serialNo: Number, //排序用
+    isChecked: Boolean //是否勾选(输出)
+});
+//特征值字段
+let eigenvalueSchema = new Schema({
+    value: String,
+    isSelected: Boolean //判断哪个特征值被选中
+});
+//项目特征字段
+let itemCharacterSchema = new Schema({
+    character: String, //特征
+    eigenvalue: [eigenvalueSchema],//特征值
+    isChecked: Boolean //是否勾选(输出)
+});
+
+module.exports = {feesSchema: feesSchema, flagsSchema: flagsSchema, jobContentSchema: jobContentSchema, itemCharacterSchema: itemCharacterSchema};

+ 1 - 0
modules/main/models/proj_counter.js

@@ -2,6 +2,7 @@
  * Created by Mai on 2017/6/13.
  * Created by Mai on 2017/6/13.
  */
  */
 
 
+let mongoose = require('mongoose');
 let baseModel = require('./base_model');
 let baseModel = require('./base_model');
 
 
 class projCounter extends baseModel {
 class projCounter extends baseModel {

+ 11 - 10
modules/pm/controllers/new_proj_controller.js

@@ -2,23 +2,24 @@
  * Created by Mai on 2017/4/24.
  * Created by Mai on 2017/4/24.
  */
  */
 
 
-let BillsTemplateData = require('../../templates/models/bills_template');
 let billsData = require('../../main/models/bills');
 let billsData = require('../../main/models/bills');
 let projCounter = require('../../main/models/proj_counter');
 let projCounter = require('../../main/models/proj_counter');
 let async = require('async');
 let async = require('async');
 
 
+import BillsTemplateModel from "../models/templates/bills_template_model";
+
 module.exports = {
 module.exports = {
-    copyTemplateData: function (tempType, newProjID, callback) {
+    copyTemplateData: async function (valuationId, newProjID, callback) {
         async.parallel([
         async.parallel([
-            function (cb) {
-                BillsTemplateData.getTemplate(tempType).then(function (templates) {
-                    let datas = [];
-                    templates.forEach(function (template) {
-                        template._doc.projectID = newProjID;
-                        datas.push(template._doc);
-                    })
-                    return billsData.insertData(datas, cb);
+            async function (cb) {
+                // 获取清单模板数据
+                let billsTemplateModel = new BillsTemplateModel();
+                let templateData = JSON.stringify(await billsTemplateModel.getTemplateDataForNewProj(valuationId));
+                let billsDatas = JSON.parse(templateData);
+                billsDatas.forEach(function (template) {
+                    template.projectID = newProjID;
                 });
                 });
+                billsData.insertData(billsDatas, callback);
             },
             },
             function (cb) {
             function (cb) {
                 projCounter.insertData({"projectID": newProjID}, cb);
                 projCounter.insertData({"projectID": newProjID}, cb);

+ 2 - 2
modules/pm/models/project_model.js

@@ -37,7 +37,7 @@ ProjectsDAO.prototype.getUserProject = function (userId, ProjId, callback) {
 }
 }
 
 
 ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
 ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
-    let data, project, updateLength = 0, hasError = false, deleteInfo = null, tempType = 1, i, newProject;
+    let data, project, updateLength = 0, hasError = false, deleteInfo = null, valuationId = "599256ba700b1b340c03805e", i, newProject;
     let updateAll = function (err) {
     let updateAll = function (err) {
             if (!err){
             if (!err){
                 updateLength += 1;
                 updateLength += 1;
@@ -61,7 +61,7 @@ ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
                 newProject = new Projects(data.updateData);
                 newProject = new Projects(data.updateData);
                 newProject.save(function (err, result) {
                 newProject.save(function (err, result) {
                     if (!err && result._doc.projType === projectType.tender) {
                     if (!err && result._doc.projType === projectType.tender) {
-                        newProjController.copyTemplateData(tempType, newProject.ID, updateAll);
+                        newProjController.copyTemplateData(valuationId, newProject.ID, updateAll);
                     } else {
                     } else {
                         updateAll(err);
                         updateAll(err);
                     }
                     }

+ 75 - 0
modules/pm/models/templates/bills_template_model.js

@@ -0,0 +1,75 @@
+/**
+ * Created by Mai on 2017/4/14.
+ * 清单模板,新建项目使用
+ */
+import BaseModel from "../../../common/base/base_model";
+import BillsTemplateSchema from "./schemas/bills_template";
+
+class BillsTemplateModel extends BaseModel {
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = BillsTemplateSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取计价类别对应的清单模板
+     * @param valuationId
+     * @returns {*}
+     */
+    async getTemplateData (valuationId) {
+        // 筛选字段
+        let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
+        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+
+        return data === null ? [] : data;
+    }
+
+    /**
+     * 新建项目时,获取计价类别对应的清单模板
+     * @param valuationId
+     * @returns {*}
+     */
+    async getTemplateDataForNewProj (valuationId) {
+        // 筛选字段
+        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
+        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+
+        return data === null ? [] : data;
+    }
+
+    async updateTemplate (valuationId, datas) {
+        try {
+            for (let data of datas) {
+                data.data.valuationId = valuationId;
+                let condition = {valuationId: valuationId, ID: data.data.ID}, result;
+                if (data.type === 'update') {
+                    result = await this.db.update(condition, data.data);
+                    if (result === undefined || result.ok ===undefined || !result.ok) {
+                        throw '更新数据错误';
+                    }
+                } else if (data.type === 'new') {
+                    result = await this.db.create(data.data);
+                    if (!result) {
+                        throw '新增数据错误';
+                    }
+                } else if (data.type === 'delete') {
+                    result = await this.db.delete(condition);
+                    if (result === undefined || result.ok ===undefined || !result.ok) {
+                        throw '删除数据错误';
+                    }
+                }
+            }
+            return true;
+        } catch (error) {
+            console.log(error);
+        }
+    }
+};
+
+export default BillsTemplateModel;

+ 35 - 0
modules/pm/models/templates/schemas/bills_template.js

@@ -0,0 +1,35 @@
+/**
+ * Created by Mai on 2017/8/17.
+ */
+import mongoose from "mongoose";
+let Schema = mongoose.Schema;
+
+let collectionName = 'temp_bills';
+
+// 标记字段
+let flagsSchema = new Schema({
+    fieldName: String,
+    flag: Number
+});
+let BillsTemplateSchema = {
+    // 树结构所需ID
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    // 编号
+    code: String,
+    // 名称
+    name: String,
+    // 单位
+    unit: String,
+    // 标记
+    flags:{
+        type: [flagsSchema],
+        default: []
+    },
+    // 所属计价ID
+    valuationId: String
+};
+
+let model = mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 80 - 13
modules/reports/controllers/rpt_controller.js

@@ -3,6 +3,7 @@
  */
  */
 
 
 let mongoose = require('mongoose');
 let mongoose = require('mongoose');
+let async = require('async');
 
 
 let JV = require('../rpt_component/jpc_value_define');
 let JV = require('../rpt_component/jpc_value_define');
 
 
@@ -13,6 +14,7 @@ let demoTemplateFacade = require('../facade/rpt_tpl_data_demo_facade');
 let JpcEx = require('../rpt_component/jpc_ex');
 let JpcEx = require('../rpt_component/jpc_ex');
 let rptUtil = require("../util/rpt_util");
 let rptUtil = require("../util/rpt_util");
 let rpt_xl_util = require('../util/rpt_excel_util');
 let rpt_xl_util = require('../util/rpt_excel_util');
+let rpt_pdf_util = require('../util/rpt_pdf_util');
 let fs = require('fs');
 let fs = require('fs');
 let strUtil = require('../../../public/stringUtil');
 let strUtil = require('../../../public/stringUtil');
 
 
@@ -27,7 +29,7 @@ let callback = function(req, res, err, data){
     }
     }
 };
 };
 
 
-function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
+function getAllPagesCommonOrg(rpt_id, pageSize, cb) {
     let rptTpl = null;
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
         rptTpl = rst;
         rptTpl = rst;
@@ -35,10 +37,12 @@ function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
             if (rptTpl.ID_KEY) {
             if (rptTpl.ID_KEY) {
                 return demoTemplateFacade.getDemoData(rptTpl.ID_KEY);
                 return demoTemplateFacade.getDemoData(rptTpl.ID_KEY);
             } else {
             } else {
-                callback(req, res, 'No report template data were found!', null);
+                //callback(req, res, 'No report template data were found!', null);
+                cb('No report template data were found!', null);
             }
             }
         } else {
         } else {
-            callback(req, res, 'No report template was found!', null);
+            //callback(req, res, 'No report template was found!', null);
+            cb('No report template was found!', null);
         }
         }
     }).then(function(tplData){
     }).then(function(tplData){
             if (tplData) {
             if (tplData) {
@@ -50,18 +54,20 @@ function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
                 let maxPages = printCom.totalPages;
                 let maxPages = printCom.totalPages;
                 let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                 let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                 if (pageRst) {
                 if (pageRst) {
-                    cb(pageRst);
+                    cb(null, pageRst);
                 } else {
                 } else {
-                    callback(req, res, "Have errors while on going...", null);
+                    //callback(req, res, "Have errors while on going...", null);
+                    cb('Have errors while on going...', null);
                 }
                 }
             } else {
             } else {
-                callback(req, res, 'No report data were found!', null);
+                //callback(req, res, 'No report data were found!', null);
+                cb('No report data were found!', null);
             }
             }
         }
         }
     );
     );
 };
 };
 
 
-function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
+function getAllPagesCommon(rpt_id, pageSize, cb) {
     let rptTpl = null;
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
         rptTpl = rst;
         rptTpl = rst;
@@ -95,10 +101,10 @@ function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
                 //return demoTemplateData.findOne({"Data_Key": rptTpl.ID_KEY}).exec();
                 //return demoTemplateData.findOne({"Data_Key": rptTpl.ID_KEY}).exec();
 
 
             } else {
             } else {
-                callback(req, res, 'No report template data were found!', null);
+                cb('No report template data were found!', null);
             }
             }
         } else {
         } else {
-            callback(req, res, 'No report template was found!', null);
+            cb('No report template was found!', null);
         }
         }
     })
     })
 };
 };
@@ -107,9 +113,9 @@ module.exports = {
     getReportAllPages: function(req, res){
     getReportAllPages: function(req, res){
         let rpt_id = req.body.ID;
         let rpt_id = req.body.ID;
         let pageSize = req.body.pageSize;
         let pageSize = req.body.pageSize;
-        getAllPagesCommonOrg(req, res, rpt_id, pageSize, function(pageRst){
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
             //fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
             //fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
-            callback(req, res, null, pageRst);
+            callback(req, res, err, pageRst);
         })
         })
     },
     },
     getExcel: function(req, res) {
     getExcel: function(req, res) {
@@ -118,8 +124,8 @@ module.exports = {
             rptName = req.params.rptName,
             rptName = req.params.rptName,
             isOneSheet = req.params.isOneSheet;
             isOneSheet = req.params.isOneSheet;
         ;
         ;
-        getAllPagesCommonOrg(req, res, rpt_id, pageSize, function(pageRst){
-            rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, function(newName){
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
+            rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, null, function(newName){
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
                 let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
                 let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
@@ -131,5 +137,66 @@ module.exports = {
                 });
                 });
             });
             });
         })
         })
+    },
+    getExcelInOneBook: function(req, res) {
+        let rpt_ids = req.params.ids.split(','),
+            pageSize = req.params.size,
+            rptName = req.params.rptName;
+        ;
+        let parallelFucs = [];
+        for (let id of rpt_ids) {
+            parallelFucs.push((function (rpt_id) {
+                return function (cb) {
+                    getAllPagesCommonOrg(rpt_id, pageSize, function (err, pageRst) {
+                        if(err){
+                            cb(err);
+                        }
+                        else{
+                            cb(null, pageRst);
+                        }
+                    })
+                }
+            })(parseInt(id)));
+        }
+        async.parallel(parallelFucs, function (err, pageRstArray) {
+            if (err) {
+                callback(req, res, '数据有误', null);
+            } else {
+                rpt_xl_util.exportExcelInOneBook(pageRstArray, pageSize, rptName, function(tmpFilePath){
+                    res.setHeader('Content-Type', 'application/vnd.openxmlformats');
+                    res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
+                    let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + tmpFilePath + '.xlsx');
+                    filestream.on('data', function(chunk) {
+                        res.write(chunk);
+                    });
+                    filestream.on('end', function() {
+                        res.end();
+                    });
+                });
+                //callback(req, res, false, '', {compilation: rst, gljLibs: gljLibsRst});
+            }
+        })
+    },
+    getPDF:function (req, res) {
+        let rpt_id = req.params.id,
+            pageSize = req.params.size,
+            rptName = req.params.rptName;
+
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
+            rpt_pdf_util.export_pdf_file(pageRst, pageSize, rptName,function (newName) {
+                res.setHeader('Content-Type', 'application/vnd.openxmlformats');
+                res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".pdf");
+
+                let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.pdf');
+                filestream.on('data', function(chunk) {
+                    res.write(chunk);
+                });
+                filestream.on('end', function() {
+                    res.end();
+                });
+            })
+
+        })
+
     }
     }
 };
 };

+ 4 - 0
modules/reports/routes/report_router.js

@@ -18,6 +18,10 @@ module.exports =function (app) {
         }
         }
     });
     });
     rptRouter.post('/getReport', reportController.getReportAllPages);
     rptRouter.post('/getReport', reportController.getReportAllPages);
+
     rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet', reportController.getExcel);
     rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet', reportController.getExcel);
+    rptRouter.get('/getExcelInOneBook/:ids/:size/:rptName', reportController.getExcelInOneBook);
+
+    rptRouter.get('/getPDF/:id/:size/:rptName', reportController.getPDF);//2/A4/07-1表
     app.use("/report_api", rptRouter);
     app.use("/report_api", rptRouter);
 }
 }

+ 4 - 1
modules/reports/rpt_component/jpc_ex.js

@@ -169,7 +169,10 @@ JpcExSrv.prototype.createNew = function(){
             rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties == null)?null:defProperties.ctrls);
             rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties == null)?null:defProperties.ctrls);
             rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties == null)?null:defProperties.styles);
             rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties == null)?null:defProperties.styles);
             rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties == null)?null:defProperties.fonts);
             rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties == null)?null:defProperties.fonts);
-            rst[JV.NODE_PAGE_INFO] = JpcCommonHelper.getPageSize(rptTpl);
+            rst[JV.NODE_PAGE_INFO] = {};
+            rst[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME];
+            rst[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE] = JpcCommonHelper.getPageSize(rptTpl);
+            rst[JV.NODE_PAGE_INFO][JV.NODE_MARGINS] = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS];
             rst.items = [];
             rst.items = [];
             let bands = JpcBand.createNew(rptTpl, defProperties);
             let bands = JpcBand.createNew(rptTpl, defProperties);
             try {
             try {

+ 230 - 0
modules/reports/util/canvas_util.js

@@ -0,0 +1,230 @@
+/**
+ * Created by chen on 2017/7/27.
+ */
+let can = require('canvas');
+let canvas = new can(1200, 900,'pdf'), fs = require('fs');
+let reportO = require('./reportOj');
+//,ctx = canvas.getContext('2d')
+/*var y = 80, x = 50;
+ctx.font = '22px Helvetica';
+ctx.fillText('node-canvas pdf', x, y);
+ctx.font = '10px Arial';
+ctx.fillText('Just a quick example of PDFs with node-canvas lonso', x, y += 20);
+ctx.globalAlpha = .5;
+ctx.fillRect(x, y += 20, 10, 10);
+ctx.fillRect(x += 20, y, 10, 10);
+ctx.fillRect(x += 20, y, 10, 10);*/
+//fs.writeFile('out.pdf', canvas.toBuffer());
+
+
+
+let JpcCanvasOutput = {
+    offsetX: 10,
+    offsetY: 10,
+    cleanCanvas: function (canvas) {
+        var ctx = canvas.getContext("2d");
+        ctx.save();
+        ctx.fillStyle="white";
+        ctx.clearRect(0,0, canvas.width, canvas.height);
+        ctx.restore();
+    },
+    drawToCanvas : function(pageObj, canvas, pageIdx) {
+        var me = this;
+        var ctx = canvas.getContext("2d");
+
+        function private_setupAreaH(area, type, fontAngle, dftFontHeight, outputPoint) {
+            var lType = type;
+            if (type != "left" && type != "right" && type != "center") lType = "left";
+            switch (lType) {
+                case "left":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    ctx.textAlign="start";
+                    break;
+                case "right":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    ctx.textAlign="end";
+                    break;
+                case "center":
+                    if (fontAngle == JV.VERTICAL_ANGLE || fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
+                    } else outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2;
+                    ctx.textAlign="center";
+                    break;
+            }
+        }
+        function private_setupAreaV(area, type, fontAngle, dftFontHeight, outputPoint) {
+            var lType = type;
+            if (type != "top" && type != "bottom" && type != "center") lType = "top";
+            switch (lType) {
+                case "top":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    break;
+                case "center":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
+                    } else outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
+                    break;
+            }
+        }
+        function private_drawText(val, area, font, control) {
+            var dftFontHeight = 12;
+            var output = [];
+            if (font) {
+                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                var dftOthers = "";
+                var dftFontBold = font[JV.FONT_PROPS[3]];
+                if (dftFontBold && dftFontBold == 'T') {
+                    dftOthers = "bold " + dftOthers ;
+                }
+                var dftFontItalic = font[JV.FONT_PROPS[4]];
+                if (dftFontItalic && dftFontItalic == 'T') {
+                    dftOthers = dftOthers + "italic ";
+                }
+                ctx.font = dftOthers + dftFontHeight + "px " + font[JV.PROP_NAME];
+            }
+            if (control) {
+                private_setupAreaH(area, control.Horizon, font.FontAngle, dftFontHeight, output);
+                private_setupAreaV(area, control.Vertical, font.FontAngle, dftFontHeight, output);
+            } else {
+                private_setupAreaH(area, "left", font.FontAngle, dftFontHeight, output);
+                private_setupAreaV(area, "bottom", font.FontAngle, dftFontHeight, output);
+            }
+            var w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+            if (font.FontAngle != "0") {
+                w = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+            }
+            ctx.save();
+            ctx.translate(output[0], output[1]);
+            if (font.FontAngle == JV.VERTICAL_ANGLE) {
+                ctx.rotate(Math.PI/2);
+            } else if (font.FontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                ctx.rotate(-Math.PI/2);
+            }
+            if (w >= ctx.measureText(val).width) {
+                ctx.fillText(val, 0, 0);
+            } else {
+                while (true) {
+                    dftFontHeight--;
+                    ctx.font = "" + dftFontHeight + "px " + font[JV.PROP_NAME];
+                    if (w >=  ctx.measureText(val).width || dftFontHeight < 6) {
+                        ctx.fillText(val, 0, 0);
+                        break;
+                    }
+                }
+            }
+            ctx.restore();
+        }
+        function private_drawCellText(cell, fonts, controls) {
+            if (cell[JV.PROP_VALUE]) {
+                var values = ("" + cell[JV.PROP_VALUE]).split('|');
+                var font = fonts[cell[JV.PROP_FONT]];
+                var control = controls[cell[JV.PROP_CONTROL]];
+                var height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+                var area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + me.offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + me.offsetY];
+                for (var i = 0; i < values.length; i++) {
+                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + me.offsetY;
+                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + me.offsetY;
+                    private_drawText(values[i], area, font, control);
+                }
+            }
+        }
+        function private_drawLine(cell, ctx, style, styleBorderDest, startP, destP, mergedBand, styles) {
+            ctx.beginPath();
+            var destStyle = style;
+            if (mergedBand) {
+                if (mergedBand[styleBorderDest] == cell[JV.PROP_AREA][styleBorderDest]) {
+                    destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
+                }
+            }
+            ctx.moveTo(cell[JV.PROP_AREA][startP[0]] + me.offsetX, cell[JV.PROP_AREA][startP[1]] + me.offsetY);
+            if (destStyle[styleBorderDest] && destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT] != 0) {
+                ctx.lineWidth = 1.0 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT];
+                ctx.strokeStyle = destStyle[styleBorderDest][JV.PROP_COLOR];
+                ctx.lineTo(cell[JV.PROP_AREA][destP[0]] + me.offsetX, cell[JV.PROP_AREA][destP[1]] + me.offsetY);
+            }
+            ctx.stroke();
+        }
+        function private_drawCell(cell, fonts, styles, controls, mergedBand) {
+            ctx.save();
+            ctx.translate(0.5,0.5);
+            var style = styles[cell[JV.PROP_STYLE]];
+            if (style) {
+                private_drawLine(cell, ctx, style, JV.PROP_TOP, [JV.PROP_LEFT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_TOP], mergedBand, styles);
+                private_drawLine(cell, ctx, style, JV.PROP_RIGHT, [JV.PROP_RIGHT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_BOTTOM], mergedBand, styles);
+                private_drawLine(cell, ctx, style, JV.PROP_BOTTOM, [JV.PROP_RIGHT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_BOTTOM], mergedBand, styles);
+                private_drawLine(cell, ctx, style, JV.PROP_LEFT, [JV.PROP_LEFT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_TOP], mergedBand, styles);
+            }
+            private_drawCellText(cell, fonts, controls);
+            ctx.restore();
+        }
+
+        for(var p=1;p<50;p++){
+            pageIdx=p;
+            if (pageObj && pageObj.items.length > 0 && canvas && pageObj.items.length >= pageIdx) {
+                var page = pageObj.items[pageIdx - 1],
+                    fonts = pageObj[JV.NODE_FONT_COLLECTION],
+                    styles = pageObj[JV.NODE_STYLE_COLLECTION],
+                    controls = pageObj[JV.NODE_CONTROL_COLLECTION],
+                    mergedBand = pageObj[JV.BAND_PROP_MERGE_BAND];
+                for (var j = 0; j < page.cells.length; j++) {
+                    var cell = page.cells[j];
+                    private_drawCell(cell, fonts, styles, controls, mergedBand);
+                }
+            }
+            ctx.addPage();
+        }
+
+        fs.writeFile('report.pdf', canvas.toBuffer());
+    },
+    drawPageBorder: function(rptTpl, canvas, resolution) {
+        var me = this;
+        var size = rptTpl[JV.NODE_PAGE_INFO].slice(0);
+        size[0] = Math.round(resolution[0] * size[0]);
+        size[1] = Math.round(resolution[0] * size[1]);
+
+        var ctx = canvas.getContext("2d");
+        ctx.save();
+        ctx.beginPath();
+        ctx.translate(0.5,0.5);
+        ctx.lineWidth = 1;
+        ctx.moveTo(me.offsetX, me.offsetY);
+        ctx.lineTo(size[0] + me.offsetX, me.offsetY);
+        ctx.lineTo(size[0] + me.offsetX, size[1] + me.offsetY);
+        ctx.lineTo(me.offsetX, size[1] + me.offsetY);
+        ctx.lineTo(me.offsetX, me.offsetY);
+        ctx.stroke();
+        ctx.restore();
+
+        ctx.fillStyle="black";
+        ctx.fillRect(size[0] + me.offsetX,10 + me.offsetY,10,size[1]);
+        ctx.fillRect(10 + me.offsetX,size[1] + me.offsetY,size[0],10);
+    }
+}
+
+
+let rpt_oj = reportO.reportObj;
+
+
+
+JpcCanvasOutput.drawToCanvas(rpt_oj,canvas,1);

BIN
modules/reports/util/pdf_base_files/Smart-italic.ttf


BIN
modules/reports/util/pdf_base_files/Smart.ttf


BIN
modules/reports/util/pdf_base_files/hwxsb.ttf


+ 49 - 0
modules/reports/util/pdf_base_files/rpt_pdf_consts.js

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

+ 59 - 0
modules/reports/util/pdfkit_test.js

@@ -0,0 +1,59 @@
+/**
+ * Created by chen on 2017/7/28.
+ */
+
+
+var pdf = require('pdfkit');
+var fs = require('fs');
+var doc = new pdf({autoFirstPage: false});
+var text = '测试,he';
+
+doc.pipe(fs.createWriteStream('测试.pdf'));
+doc.font('simsunB.ttf');
+
+for(var p=0;p<50;p++){
+    doc.addPage({size:[1200,900]});
+
+    doc.rect(30,113,76,609).lineWidth(0.5).strokeColor('black').stroke();
+    doc.text('报表报表报表',42,717,{ height: 100, width: 500,align: 'left'});
+
+
+   /* let width = 70;
+    let height=20;
+    let j = 100;
+    let sum = 0;
+    for(i=0;i<400;i++){
+        if(i%15==0){
+            j+=height;
+            sum = 0;
+        }
+        sum =sum+width;
+        let  x = sum;
+        let y  = j;
+        doc.rect(x,y,width,height).lineWidth(0.5).strokeColor('black').stroke();
+      /!*  doc.lineWidth(1.5);
+        doc.moveTo(x,y).lineTo(x,y+height);
+        doc.lineTo(x+width,y+height);
+        doc.lineTo(x+width,y);
+        doc.lineTo(x,y)
+        doc.strokeColor('black').stroke();*!/
+
+
+        doc.fontSize(12);
+        doc.text(text,x,5+y,{
+            height: height,
+            width: width,
+            align: 'right'});
+
+        // doc.text('报表文件',100,100);
+    }*/
+    doc.save();
+  /*  doc.fontSize(20);
+    doc.rotate(-20,{origin:[400, 105]})
+    doc.text('报表报表报表',300,110,{ height: 100, width: 500,align: 'left'});*/
+    doc.restore();
+}
+
+
+
+doc.end();

+ 144 - 17
modules/reports/util/rpt_excel_util.js

@@ -7,6 +7,7 @@ let JSZip = require("jszip");
 let strUtil = require('../../../public/stringUtil');
 let strUtil = require('../../../public/stringUtil');
 let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
 let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
 let DPI = jpcCmnHelper.getScreenDPI()[0];
 let DPI = jpcCmnHelper.getScreenDPI()[0];
+let fsUtil = require('../../../public/fsUtil');
 const dftHeadXml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
 const dftHeadXml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
 
 
 function writeContentTypes(sheets, isSinglePage) {
 function writeContentTypes(sheets, isSinglePage) {
@@ -331,6 +332,7 @@ function writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     let rst = [], xPos = [], yPos = [], yMultiPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     let rst = [], xPos = [], yPos = [], yMultiPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     let cacheBorderCell = {};
     let cacheBorderCell = {};
+    let currentPageMergePos = null;
     let private_pre_analyze_pos = function(){
     let private_pre_analyze_pos = function(){
         let cell, pos;
         let cell, pos;
         let self_analyze_sheet_pos = function (theShtData, theXPos, theYPos) {
         let self_analyze_sheet_pos = function (theShtData, theXPos, theYPos) {
@@ -446,22 +448,22 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         borderLineWidths.push(border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
         if (sheetBorder[JV.PROP_LEFT] && sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_LEFT] && sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT, true));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_RIGHT] && sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_RIGHT] && sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT, true));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_TOP] && sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_TOP] && sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP, false));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_BOTTOM] && sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_BOTTOM] && sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM, false));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
@@ -473,14 +475,45 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         }
         }
         return rst;
         return rst;
     };
     };
-    let private_chkAndGetMergeLine = function(cell, sheetBorder, borderStr) {
+    let private_chkAndGetMergeLine = function(cell, sheetBorder, borderStr, needFurtherChk) {
         let rst = 0, mergeBorder = pageData[JV.BAND_PROP_MERGE_BAND];
         let rst = 0, mergeBorder = pageData[JV.BAND_PROP_MERGE_BAND];
-        if (sheetBorder[borderStr] && sheetBorder[borderStr][JV.PROP_LINE_WEIGHT] != undefined) {
+        if (sheetBorder[borderStr] && sheetBorder[borderStr][JV.PROP_LINE_WEIGHT] !== undefined) {
             rst = sheetBorder[borderStr][JV.PROP_LINE_WEIGHT];
             rst = sheetBorder[borderStr][JV.PROP_LINE_WEIGHT];
         }
         }
-        if (cell[JV.PROP_AREA][borderStr] == mergeBorder[borderStr]) {
-            let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
-            rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+        if (currentPageMergePos) {
+            let side = currentPageMergePos[borderStr];
+            if (side.indexOf(cell[JV.PROP_AREA][borderStr]) >= 0) {
+                if (needFurtherChk) {
+                    let topSide = currentPageMergePos[JV.PROP_TOP];
+                    let bottomSide = currentPageMergePos[JV.PROP_BOTTOM];
+                    for (let i = 0; i < topSide.length; i++) {
+                        if (cell[JV.PROP_AREA][JV.PROP_TOP] >= topSide[i]) {
+                            if (cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= bottomSide[i]) {
+                                let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                                rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                                break;
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+                } else {
+                    let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                    rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                }
+            }
+        } else {
+            if (cell[JV.PROP_AREA][borderStr] === mergeBorder[borderStr]) {
+                let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                if (needFurtherChk) {
+                    if (cell[JV.PROP_AREA][JV.PROP_TOP] >= mergeBorder[JV.PROP_TOP] &&
+                        cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= mergeBorder[JV.PROP_BOTTOM]) {
+                        rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                    }
+                } else {
+                    rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                }
+            }
         }
         }
         return parseInt(rst);
         return parseInt(rst);
     };
     };
@@ -503,10 +536,10 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         }
         }
         let sheetBorder = pageData[JV.NODE_STYLE_COLLECTION][cell.style];
         let sheetBorder = pageData[JV.NODE_STYLE_COLLECTION][cell.style];
         let mergedBorder = private_getIniBorder();
         let mergedBorder = private_getIniBorder();
-        mergedBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT);
-        mergedBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT);
-        mergedBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP);
-        mergedBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM);
+        mergedBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT, true);
+        mergedBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT, true);
+        mergedBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP, false);
+        mergedBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM, false);
         for (let i = 0; i < stylesObj.borders.length; i++) {
         for (let i = 0; i < stylesObj.borders.length; i++) {
             let border = stylesObj.borders[i];
             let border = stylesObj.borders[i];
             if (private_checkBorder(cell, border, mergedBorder)) {
             if (private_checkBorder(cell, border, mergedBorder)) {
@@ -723,12 +756,14 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         private_cacheMergeBandBorderIdxs();
         private_cacheMergeBandBorderIdxs();
         if (sheetData) {
         if (sheetData) {
             //current sheet data
             //current sheet data
+            currentPageMergePos = sheetData[JV.PAGE_SPECIAL_MERGE_POS];
             self_setDataEx(sheetData, yPos, 0);
             self_setDataEx(sheetData, yPos, 0);
         } else {
         } else {
             //total data in one sheet
             //total data in one sheet
             let cnt = 0;
             let cnt = 0;
             for (let i = 0; i < pageData.items.length; i++) {
             for (let i = 0; i < pageData.items.length; i++) {
                 let shtItemData = pageData.items[i];
                 let shtItemData = pageData.items[i];
+                currentPageMergePos = shtItemData[JV.PAGE_SPECIAL_MERGE_POS];
                 let tmpPos = yMultiPos[i];
                 let tmpPos = yMultiPos[i];
                 cellIdx = 0;
                 cellIdx = 0;
                 self_setDataEx(shtItemData, tmpPos, cnt);
                 self_setDataEx(shtItemData, tmpPos, cnt);
@@ -758,15 +793,30 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     if (paperSizeIdx >= 0) {
     if (paperSizeIdx >= 0) {
         pStr = 'paperSize="' + JV.PAGES_SIZE_IDX[paperSizeIdx] + '"';
         pStr = 'paperSize="' + JV.PAGES_SIZE_IDX[paperSizeIdx] + '"';
     }
     }
-    let orientationStr = (pageData[JV.NODE_PAGE_INFO][0] > pageData[JV.NODE_PAGE_INFO][1])?'landscape':'portrait';
+    let orientationStr = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] > pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?'landscape':'portrait';
     rst.push('<pageSetup ' + pStr + ' fitToWidth="0" fitToHeight="0" orientation="' + orientationStr + '" />');
     rst.push('<pageSetup ' + pStr + ' fitToWidth="0" fitToHeight="0" orientation="' + orientationStr + '" />');
     rst.push('<headerFooter alignWithMargins="0"/>');
     rst.push('<headerFooter alignWithMargins="0"/>');
     rst.push('</worksheet>');
     rst.push('</worksheet>');
     return rst;
     return rst;
 }
 }
 
 
+function mergeProperties(orgObj, newObj) {
+    let orgPropArr = [], newPropArr = [];
+    for (let p in orgObj) {
+        orgPropArr.push(p);
+    }
+    for (let p in newObj) {
+        newPropArr.push(p);
+    }
+    for (let i = 0; i < newPropArr.length; i++) {
+        if (orgPropArr.indexOf(newPropArr[i]) < 0) {
+            orgObj[newPropArr[i]] = newObj[newPropArr[i]];
+        }
+    }
+}
+
 module.exports = {
 module.exports = {
-    exportExcel: function (pageData, paperSize, fName, options, callback) {
+    exportExcel: function (pageData, paperSize, fName, options, custSheetNames, callback) {
         let rptOptions = ({singlePage: false, fileName: 'report'});
         let rptOptions = ({singlePage: false, fileName: 'report'});
         if (options === 'true') {
         if (options === 'true') {
             rptOptions.singlePage = true;
             rptOptions.singlePage = true;
@@ -776,8 +826,14 @@ module.exports = {
         if (isSinglePage) {
         if (isSinglePage) {
             sheets.push({sheetName: '全部页'});
             sheets.push({sheetName: '全部页'});
         } else {
         } else {
-            for (let i = 0; i < pageData.items.length; i++) {
-                sheets.push({sheetName: '第' + (i + 1) + '页'});
+            if (custSheetNames && custSheetNames.length === pageData.items.length) {
+                for (let i = 0; i < pageData.items.length; i++) {
+                    sheets.push({sheetName: custSheetNames[i]});
+                }
+            } else {
+                for (let i = 0; i < pageData.items.length; i++) {
+                    sheets.push({sheetName: '第' + (i + 1) + '页'});
+                }
             }
             }
         }
         }
         //1.
         //1.
@@ -849,5 +905,76 @@ module.exports = {
             //return zip.generateNodeStream({type:'nodebuffer',streamFiles:true});
             //return zip.generateNodeStream({type:'nodebuffer',streamFiles:true});
             return zip;
             return zip;
         }
         }
+    },
+
+    exportExcelInOneBook: function (pageDataArray, paperSize, fName, callback) {
+        let me = this, newPageData = {};
+        //1. 重新编排一下数据,把一份报表的pageData合并到一起作为一个Sheet输出(需要重新调整数据纵向坐标),多份报表数据就形成多个Sheet
+        //   -- 简单来说,就是重新包装数据
+        try {
+            // 1.1 newPageData外围属性
+            let newContrl = {}, newFont = {}, newStyle = {};
+            for (let i = 0; i < pageDataArray.length; i++) {
+                mergeProperties(newContrl, pageDataArray[i][JV.NODE_CONTROL_COLLECTION]);
+                mergeProperties(newFont, pageDataArray[i][JV.NODE_FONT_COLLECTION]);
+                mergeProperties(newStyle, pageDataArray[i][JV.NODE_STYLE_COLLECTION]);
+            }
+            newPageData[JV.NODE_CONTROL_COLLECTION] = newContrl;
+            newPageData[JV.NODE_FONT_COLLECTION] = newFont;
+            newPageData[JV.NODE_STYLE_COLLECTION] = newStyle;
+            newPageData[JV.NODE_PAGE_INFO] = pageDataArray[0][JV.NODE_PAGE_INFO];
+            newPageData[JV.BAND_PROP_MERGE_BAND] = pageDataArray[0][JV.BAND_PROP_MERGE_BAND];
+
+            // 1.2 重新设置pageDataArray的各个cell的Top/Bottom坐标
+            let sheetNames = [], newPagePos = [];
+            for (let i = 0; i < pageDataArray.length; i++) {
+                let offsetY = 0;
+                let mergeBand = {};
+                mergeBand[JV.PROP_LEFT] = [];
+                mergeBand[JV.PROP_RIGHT] = [];
+                mergeBand[JV.PROP_TOP] = [];
+                mergeBand[JV.PROP_BOTTOM] = [];
+                newPagePos.push(mergeBand);
+                mergeBand[JV.PROP_LEFT].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT]);
+                mergeBand[JV.PROP_RIGHT].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT]);
+                sheetNames.push(pageDataArray[i][JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
+
+                for (let j = 0; j < pageDataArray[i].items.length; j++) {
+                    let maxY = 0, minY = 100000;
+                    mergeBand[JV.PROP_TOP].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] + offsetY);
+                    mergeBand[JV.PROP_BOTTOM].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM] + offsetY);
+                    for (let k = 0; k < pageDataArray[i].items[j].cells.length; k++) {
+                        if (maxY < pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM]) {
+                            maxY = pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM];
+                        }
+                        if (minY > pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP]) {
+                            minY = pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP];
+                        }
+                        pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM] += offsetY;
+                        pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP] += offsetY;
+                    }
+                    offsetY += (maxY - minY);
+                }
+            }
+            //2. newPageData的items属性
+            newPageData.items = [];
+            for (let i = 0; i < pageDataArray.length; i++) {
+                let pageItem = {};
+                pageItem[JV.PROP_PAGE_SEQ] = i + 1;
+                pageItem[JV.PROP_CELLS] = [];
+                for (let j = 0; j < pageDataArray[i].items.length; j++) {
+                    for (let k = 0; k < pageDataArray[i].items[j].cells.length; k++) {
+                        pageItem[JV.PROP_CELLS].push(pageDataArray[i].items[j].cells[k]);
+                    }
+                }
+                pageItem[JV.PAGE_SPECIAL_MERGE_POS] = newPagePos[i];
+                newPageData.items.push(pageItem);
+            }
+            //3. everything is ok, then call me
+            me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, callback);
+            fsUtil.wirteObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
+        } catch (e) {
+            console.log(e);
+        }
     }
     }
 }
 }

+ 202 - 0
modules/reports/util/rpt_pdf_util.js

@@ -0,0 +1,202 @@
+/**
+ * Created by chen on 2017/8/16.
+ */
+/**
+ * Created by zhang on 2017/8/14.
+ */
+
+const prf_cons = require('./pdf_base_files/rpt_pdf_consts');
+var pdf = require('pdfkit');
+var fs = require('fs');
+let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
+let DPI = jpcCmnHelper.getScreenDPI()[0];
+//let JV = prf_cons.JV;
+let JV = require('../rpt_component/jpc_value_define');
+
+module.exports ={
+    export_pdf_file:export_pdf_file
+}
+
+
+function export_pdf_file (pageData, paperSize, fName, callback) {
+    let offsetX= 10;
+    let offsetY=10;
+    var doc = new pdf({autoFirstPage: false});
+    let newName = '' + (new Date()).valueOf();
+    let stream = doc.pipe(fs.createWriteStream(__dirname.slice(0, __dirname.length - 21) + '/tmp/'+newName+'.pdf'));
+    let pageObj = pageData;
+    // doc.rect(5,5,1190,890).lineWidth(1).strokeColor('black').stroke();//边框
+    let paperSizeIdx = JV.PAGES_SIZE_STR.indexOf(paperSize);
+    let size = JV.PAGES_SIZE[paperSizeIdx];
+
+    if (pageObj && pageObj.items.length > 0 ) {
+        for(let i=0;i<pageObj.items.length;i++){
+            doc.addPage({size:[size[1]*DPI,size[0]*DPI]});
+            var page = pageObj.items[i],
+                fonts = pageObj[JV.NODE_FONT_COLLECTION],
+                styles = pageObj[JV.NODE_STYLE_COLLECTION],
+                controls = pageObj[JV.NODE_CONTROL_COLLECTION],
+                mergedBand = pageObj[JV.BAND_PROP_MERGE_BAND];
+
+            for (var j = 0; j < page.cells.length; j++) {
+                var cell = page.cells[j];
+                private_drawCell(cell, fonts, styles, controls, mergedBand);
+            }
+        }
+    }
+    doc.end();
+    stream.on('finish',function () {
+        console.log(newName + ".pdf was written.");
+        callback(newName);
+    })
+
+
+    function private_drawCell(cell, fonts, styles, controls, mergedBand) {
+        doc.save();
+        //doc.translate(0.5,0.5);
+        var style = styles[cell[JV.PROP_STYLE]];
+        if (style) {
+            private_drawLine(cell, doc, style, JV.PROP_TOP, [JV.PROP_LEFT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_TOP], mergedBand, styles);
+            private_drawLine(cell, doc, style, JV.PROP_RIGHT, [JV.PROP_RIGHT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_BOTTOM], mergedBand, styles);
+            private_drawLine(cell, doc, style, JV.PROP_BOTTOM, [JV.PROP_RIGHT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_BOTTOM], mergedBand, styles);
+            private_drawLine(cell, doc, style, JV.PROP_LEFT, [JV.PROP_LEFT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_TOP], mergedBand, styles);
+        }
+        private_drawCellText(cell, fonts, controls);
+        doc.restore();
+
+    }
+
+    function private_drawLine(cell, doc, style, styleBorderDest, startP, destP, mergedBand, styles) {
+        //doc.beginPath();
+        var destStyle = style;
+        if (mergedBand) {
+            if (mergedBand[styleBorderDest] == cell[JV.PROP_AREA][styleBorderDest]) {
+                destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
+            }
+        }
+        doc.moveTo(cell[JV.PROP_AREA][startP[0]] + offsetX, cell[JV.PROP_AREA][startP[1]] + offsetY);
+        if (destStyle[styleBorderDest] && destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT] != 0) {
+            doc.lineWidth(1.0 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]);
+            doc.lineTo(cell[JV.PROP_AREA][destP[0]] + offsetX, cell[JV.PROP_AREA][destP[1]] + offsetY);
+            doc.strokeColor(destStyle[styleBorderDest][JV.PROP_COLOR]);
+        }
+        doc.stroke();
+    }
+    function private_drawCellText(cell, fonts, controls) {
+        if (cell[JV.PROP_VALUE]) {
+            var values = ("" + cell[JV.PROP_VALUE]).split('|');
+            var font = fonts[cell[JV.PROP_FONT]];
+            var control = controls[cell[JV.PROP_CONTROL]];
+            var height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+            var 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];
+            for (var i = 0; i < values.length; i++) {
+                area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + offsetY;
+                area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + offsetY;
+                private_drawText(values[i], area, font, control);
+            }
+        }
+    }
+
+    function private_drawText(val, area, font, control) {
+        var dftFontHeight = 12;
+        var output = [];
+        if (font) {
+            dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+            var dftFontBold = font[JV.FONT_PROPS[3]];
+            var dftFontItalic = font[JV.FONT_PROPS[4]];
+            if (dftFontBold && dftFontBold == 'T') {
+                doc.font(__dirname+'/pdf_base_files/hwxsb.ttf');
+            }else if(dftFontItalic && dftFontItalic == 'T'){
+                doc.font(__dirname+'/pdf_base_files/Smart-italic.ttf');
+            }else {
+                doc.font(__dirname+'/pdf_base_files/Smart.ttf');
+            }
+            doc.fontSize(dftFontHeight);
+        }
+        var options={};
+        if (control) {
+            private_setupAreaH(area, control.Horizon, font.FontAngle, dftFontHeight, output,options);
+            private_setupAreaV(area, control.Vertical, font.FontAngle, dftFontHeight, output);
+        } else {
+            private_setupAreaH(area, "left", font.FontAngle, dftFontHeight, output,options);
+            private_setupAreaV(area, "bottom", font.FontAngle, dftFontHeight, output);
+        }
+        var w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+        if (font.FontAngle != "0") {
+            w = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+        }
+        doc.save();
+        //doc.translate(output[0], output[1]);
+        if (w >= doc.widthOfString(val)) {
+            options.width=w;
+            options.height=dftFontHeight;
+        } else {
+            while (true) {
+                dftFontHeight--;
+                doc.fontSize(dftFontHeight);
+                if (w >= doc.widthOfString(val) || dftFontHeight < 6) {
+                    options.width=w;
+                    options.height=dftFontHeight;
+                    break;
+                }
+            }
+        }
+
+        var rotateOptions;
+        if (font.FontAngle != "0") {
+            if (control){
+                rotateOptions=private_setupAreaRotateOption(area,w,control.Vertical,dftFontHeight, output);
+            }else {
+                rotateOptions=private_setupAreaRotateOption(area,w,"bottom",dftFontHeight, output);
+            }
+            doc.rotate(font.FontAngle,rotateOptions);
+        }
+        doc.text(val,output[0], output[1],options);
+        doc.restore();
+    }
+
+    function private_setupAreaH(area, type, fontAngle, dftFontHeight, outputPoint,options) {
+        var lType = type;
+        if (type != "left" && type != "right" && type != "center") lType = "left";
+        options.align=lType;
+        outputPoint[0]=1 * area[JV.IDX_LEFT]+ JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+    }
+
+    function private_setupAreaV(area, type, fontAngle, dftFontHeight, outputPoint) {
+        var lType = type;
+        if (type != "top" && type != "bottom" && type != "center") lType = "top";
+        switch (lType) {
+            case "top":
+                outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                break;
+            case "bottom":
+                outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]-dftFontHeight;
+                break;
+            case "center":
+                outputPoint[1] = 1 * area[JV.IDX_TOP] + (1 * area[JV.IDX_BOTTOM]-1 * area[JV.IDX_TOP]- dftFontHeight) / 2;
+                break;
+        }
+    }
+
+    function private_setupAreaRotateOption(area,w, type="top",dftFontHeight,outputPoint){
+        var x = (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT])/2+area[JV.IDX_LEFT];
+        var y =(area[JV.IDX_BOTTOM] - area[JV.IDX_TOP])/2+ area[JV.IDX_TOP];
+        var rotateOptions = {origin:[x,y]};
+        var h = area[JV.IDX_RIGHT] - area[JV.IDX_LEFT];
+        outputPoint[0]=x-w/2+JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+        var lType = type;
+        switch (lType) {
+            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;
+    }
+
+}

+ 2 - 1
package.json

@@ -28,7 +28,8 @@
     "socket.io": "^2.0.3",
     "socket.io": "^2.0.3",
     "ua-parser-js": "^0.7.14",
     "ua-parser-js": "^0.7.14",
     "uuid": "^3.1.0",
     "uuid": "^3.1.0",
-    "ioredis":"^3.1.4"
+    "ioredis":"^3.1.4",
+    "pdfkit": "^0.8.2"
   },
   },
   "scripts": {
   "scripts": {
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js"
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js"

+ 7 - 0
public/fsUtil.js

@@ -24,5 +24,12 @@ module.exports = {
                 console.log('Write file: ' + filePath + ' ok!');
                 console.log('Write file: ' + filePath + ' ok!');
             });
             });
         }
         }
+    },
+    wirteObjToFile: function(obj, filePath) {
+        if (obj) {
+            let arr = [];
+            arr.push(JSON.stringify(obj));
+            this.writeArrayToFile(arr, filePath);
+        }
     }
     }
 }
 }

+ 3 - 0
public/web/rpt_value_define.js

@@ -35,6 +35,7 @@ let JV = {
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO_RPT_NAME: "报表名称",
     NODE_MAIN_INFO_RPT_NAME: "报表名称",
     NODE_PAGE_INFO: "打印页面_信息",
     NODE_PAGE_INFO: "打印页面_信息",
+    NODE_PAGE_SIZE: "纸张宽高",
     NODE_MARGINS: "页边距",
     NODE_MARGINS: "页边距",
 
 
     NODE_FONT_COLLECTION: "font_collection",
     NODE_FONT_COLLECTION: "font_collection",
@@ -192,8 +193,10 @@ let JV = {
     OFFSET_IDX_BOTTOM: 3,
     OFFSET_IDX_BOTTOM: 3,
 
 
     PROP_PAGE_SEQ: "page_seq",
     PROP_PAGE_SEQ: "page_seq",
+    PROP_CELLS: "cells",
 
 
     PAGE_SELF_DEFINE: "自定义",
     PAGE_SELF_DEFINE: "自定义",
+    PAGE_SPECIAL_MERGE_POS: "page_merge_pos",
 
 
     PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
     PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
     PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],
     PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],

+ 13 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -3,6 +3,16 @@
  */
  */
 
 
 var TREE_SHEET_HELPER = {
 var TREE_SHEET_HELPER = {
+    createNewSpread: function (obj) {
+        var spread = new GC.Spread.Sheets.Workbook(obj, {sheetCount: 1});
+        spread.options.tabStripVisible = false;
+        spread.options.scrollbarMaxAlign = true;
+        spread.options.cutCopyIndicatorVisible = false;
+        spread.options.allowCopyPasteExcelStyle = false;
+        spread.options.allowUserDragDrop = false;
+        spread.getActiveSheet().setRowCount(3);
+        return spread;
+    },
     getSheetCellStyle: function (setting) {
     getSheetCellStyle: function (setting) {
         var style = new GC.Spread.Sheets.Style();
         var style = new GC.Spread.Sheets.Style();
         //style.locked = setting.readOnly ? true : false;
         //style.locked = setting.readOnly ? true : false;
@@ -102,6 +112,9 @@ var TREE_SHEET_HELPER = {
                 } else {
                 } else {
                     cell.value(getFieldText2());
                     cell.value(getFieldText2());
                 }
                 }
+                if (colSetting.data.cellType) {
+                    cell.cellType(colSetting.data.cellType);
+                }
                 if (colSetting.readOnly) {
                 if (colSetting.readOnly) {
                     if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
                     if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
                         cell.locked(colSetting.readOnly(node));
                         cell.locked(colSetting.readOnly(node));

+ 4 - 3
test/tmp_data/bills_grid_setting.js

@@ -102,8 +102,8 @@ var BillsGridSetting ={
             }
             }
         },
         },
         {
         {
-            "width":40,
-            "readOnly":false,
+            "width":60,
+            "readOnly":'readOnly.ration',
             "head":{
             "head":{
                 "titleNames":[
                 "titleNames":[
                     "计量\n单位"
                     "计量\n单位"
@@ -131,7 +131,8 @@ var BillsGridSetting ={
                 "field":"unit",
                 "field":"unit",
                 "vAlign":1,
                 "vAlign":1,
                 "hAlign":1,
                 "hAlign":1,
-                "font":"Arial"
+                "font":"Arial",
+                "cellType": 'cellType.unit'
             }
             }
         },
         },
         {
         {

+ 34 - 29
web/building_saas/complementary_glj_lib/js/components.js

@@ -43,38 +43,43 @@ let componentOprObj = {
         let thisComponent = me.currentCache[args.row];
         let thisComponent = me.currentCache[args.row];
         thisComponent.isChecked = val;
         thisComponent.isChecked = val;
         console.log(val);
         console.log(val);
-        //维护选中组成物列表
-        if(val === true){
-            //解决复选框编辑状态的暂时方法todo
-            let isExist = false;
-            for(let i = 0, len = me.selectedList.length; i < len; i++){
-                if(me.selectedList[i].ID === thisComponent.ID){
-                    isExist = true;
-                    break;
-                }
-            }
-            if(!isExist){
-                me.selectedList.push(thisComponent);
-            }
+        if(args.sheet.isEditing()){
+            args.sheet.endEdit(true);
         }
         }
-        else if(val === false){
-            for(let i = 0, len = me.selectedList.length; i < len; i++){
-                if(me.selectedList[i].ID === thisComponent.ID){
-                    me.selectedList.splice(i, 1);
-                    break;
+        else{
+            //维护选中组成物列表
+            if(val === true){
+                //解决复选框编辑状态的暂时方法todo
+                let isExist = false;
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    if(me.selectedList[i].ID === thisComponent.ID){
+                        isExist = true;
+                        break;
+                    }
+                }
+                if(!isExist){
+                    me.selectedList.push(thisComponent);
                 }
                 }
             }
             }
-            if($("input[name='glj']:checked").val() === 'selectedGljs'){//radio为已选工料机时
-                me.showGljList = [];
-                me.setShowGljList(me.selectedList, false);
-                re.sortGlj(me.showGljList);
-                //重新显示
-                me.showGljItems(me.showGljList, me.gljCurTypeId);
-                if (re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {//更新cache
-                    me.currentOprParent = 1;
-                    me.currentCache = me.getParentCache(re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
-                } else {
-                    me.currentCache = me.getCache();
+            else if(val === false){
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    if(me.selectedList[i].ID === thisComponent.ID){
+                        me.selectedList.splice(i, 1);
+                        break;
+                    }
+                }
+                if($("input[name='glj']:checked").val() === 'selectedGljs'){//radio为已选工料机时
+                    me.showGljList = [];
+                    me.setShowGljList(me.selectedList, false);
+                    re.sortGlj(me.showGljList);
+                    //重新显示
+                    me.showGljItems(me.showGljList, me.gljCurTypeId);
+                    if (re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {//更新cache
+                        me.currentOprParent = 1;
+                        me.currentCache = me.getParentCache(re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
+                    } else {
+                        me.currentCache = me.getCache();
+                    }
                 }
                 }
             }
             }
         }
         }

+ 2 - 2
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -83,7 +83,7 @@ let gljComponentOprObj = {
                     return {
                     return {
                         callback: function(){},
                         callback: function(){},
                         items: {
                         items: {
-                            "insert": {name: "插入", disabled: insertDis, callback: function (key, opt) {
+                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
                                 //默认radio所有工料机
                                 //默认radio所有工料机
                                 co.initRadio();
                                 co.initRadio();
                                 co.gljCurTypeId = null;
                                 co.gljCurTypeId = null;
@@ -95,7 +95,7 @@ let gljComponentOprObj = {
                                 //弹出窗口
                                 //弹出窗口
                                 $('#componentBtn').click();
                                 $('#componentBtn').click();
                             }},
                             }},
-                            "delete": {name: "删除", disabled: delDis, callback: function (key, opt) {
+                            "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
                                 //删除
                                 //删除
                                 let deleteObj = that.currentComponent[target.row];
                                 let deleteObj = that.currentComponent[target.row];
                                 let gljComponent = that.currentGlj.component;
                                 let gljComponent = that.currentGlj.component;

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

@@ -154,12 +154,27 @@
                                   <li class="nav-item">
                                   <li class="nav-item">
                                       <a class="nav-link" id="linkDESM" data-toggle="tab" href="#subSpread" role="tab">定额说明</a>
                                       <a class="nav-link" id="linkDESM" data-toggle="tab" href="#subSpread" role="tab">定额说明</a>
                                   </li>
                                   </li>
+                                  <li class="nav-item">
+                                      <a class="nav-link" id="linkTZJNR" data-toggle="tab" href="#subSpread" role="tab">特征及内容</a>
+                                  </li>
                               </ul>
                               </ul>
                               <!-- Tab panes -->
                               <!-- Tab panes -->
                               <div class="tab-content">
                               <div class="tab-content">
                                   <div class="tab-pane active" id="gl" role="tabpanel">
                                   <div class="tab-pane active" id="gl" role="tabpanel">
                                       <div class="main-data-bottom ovf-hidden" id="subSpread">
                                       <div class="main-data-bottom ovf-hidden" id="subSpread">
                                       </div>
                                       </div>
+                                      <div id="tzjnrCon" class="row" style="display: none">
+                                          <div class="col-6">
+                                              <div class="row">
+                                                  <div class="main-data-bottom ovf-hidden col-5" id="jobSpread">
+                                                  </div>
+                                                  <div class="main-data-bottom ovf-hidden col-7" id="itemSpread">
+                                                  </div>
+                                              </div>
+                                          </div>
+                                          <div class="col-6">
+                                          </div>
+                                      </div>
                                   </div>
                                   </div>
                               </div>
                               </div>
                           </div>
                           </div>
@@ -547,6 +562,7 @@
     <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
     <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_cfg_const.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_cfg_const.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/views/character_content_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/glj_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/glj_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/sub_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/sub_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/fee_rate_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/fee_rate_view.js"></script>

+ 426 - 0
web/building_saas/main/js/views/character_content_view.js

@@ -0,0 +1,426 @@
+/**
+ * Created by Zhong on 2017/8/31.
+ * 特征及内容
+ */
+let contentOprObj = {
+    workBook: null,
+    currentCache: [],//按照serialNo排序
+    setting: {
+        header: [
+            {headerName:"工作内容",headerWidth:160,dataCode:"content", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"输出",headerWidth:80,dataCode:"isChecked", cellType:"checkBox", hAlign: "center", vAlign: "center"}
+        ]
+    },
+    buildSheet: function(container) {
+        let me = contentOprObj;
+        me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
+        me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+        me.onContextmenuOpr();//右键菜单
+    },
+    //显示在jobSpread的数据
+    showContentData: function (sheet, setting, datas) {
+        sheetCommonObj.showData(sheet, setting, datas);
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = 0, len = datas.length; i < len; i++){
+            sheet.getCell(i, 0).locked(true);
+        }
+        sheet.resumePaint();
+        sheet.suspendEvent();
+    },
+    //显示到清单工作内容列的数据
+    getColData: function (jobsArr) {
+        let me = contentOprObj;
+        let rstStr = "", count = 0;
+        for(let i = 0, len = jobsArr.length; i < len; i++){
+            if(jobsArr[i].isChecked === true){
+                count ++;
+                if(count === 1){
+                    rstStr += "“";
+                }
+                else{
+                    rstStr += " ";
+                }
+                rstStr += count + " " + jobsArr[i].content + "\n";
+            }
+        }
+        if(rstStr.trim().length > 0){
+            let reg = /\n+$/g;
+            let newStr = rstStr.replace(reg, "”");
+            return newStr;
+        }
+        return null;
+    },
+    upMove: function (rowIdx) {
+        let me = contentOprObj;
+        let thisObj = me.currentCache[rowIdx],
+            preObj = me.currentCache[rowIdx - 1],
+            temp, contentTxt;
+        temp = thisObj.serialNo;
+        thisObj.serialNo = preObj.serialNo;
+        preObj.serialNo = temp;
+        me.sortCache(me.currentCache);
+        if(thisObj.isChecked === true && preObj.isChecked === true){
+            me.refreshColData = true;
+            contentTxt = me.getColData(me.currentCache);
+        }
+        me.updateContent(me.currentCache, contentTxt);
+    },
+    downMove: function (rowIdx) {
+        let me = contentOprObj;
+        let thisObj = me.currentCache[rowIdx],
+            nextObj = me.currentCache[rowIdx + 1],
+            temp, contentTxt;
+        temp = thisObj.serialNo;
+        thisObj.serialNo = nextObj.serialNo;
+        nextObj.serialNo = temp;
+        me.sortCache(me.currentCache);
+        if(thisObj.isChecked === true && nextObj.isChecked === true){
+            me.refreshColData = true;
+            contentTxt = me.getColData(me.currentCache);
+        }
+        me.updateContent(me.currentCache, contentTxt);
+    },
+    deleteContent: function (rowIdx) {
+        let me = contentOprObj;
+        let deleteObj = me.currentCache[rowIdx];
+        let contentTxt;
+        me.currentCache.splice(rowIdx, 1);
+        if(deleteObj.isChecked === true){//需要刷新显示
+            me.refreshColData = true;
+            contentTxt = me.getColData(me.currentCache);
+        }
+        me.updateContent(me.currentCache, contentTxt);
+    },
+    //只有空行时才可以输入,即是新增时用,新增的空行只有输入了值,才保存
+    onEditEnded: function (sender, args) {
+        let me = contentOprObj;
+        let preObj = me.currentCache.length > 0 ?  me.currentCache[me.currentCache.length - 1] : null;
+        let contentTxt;
+        if(args.editingText.toString().trim().length > 0){
+            let newObj = {content: args.editingText, isChecked: args.sheet.getValue(args.row, 1)};
+            newObj.serialNo = preObj ? preObj.serialNo + 1 : 1;//得到新增对象的排序号
+            me.currentCache.push(newObj);
+            if(newObj.isChecked === true){//可能编辑内容前就打勾
+                me.refreshColData = true;
+                contentTxt = me.getColData(me.currentCache);
+            }
+            me.updateContent(me.currentCache, contentTxt);
+        }
+    },
+    //复选框控制输出
+    onButtonClicked: function (sender, args) {
+        let me = contentOprObj, contentTxt;
+        if(args.sheet.isEditing()){
+            args.sheet.endEdit(true);
+        }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        if(me.currentCache.length > args.row){
+            me.currentCache[args.row].isChecked = isChecked;
+            me.refreshColData = true;
+            contentTxt = me.getColData(me.currentCache);
+            me.updateContent(me.currentCache, contentTxt);
+        }
+        //else的情况就是新增
+    },
+    sortCache: function (cacheArr) {
+        cacheArr.sort(function (a, b) {
+            let rst = 0;
+            if(a.serialNo > b.serialNo){
+                rst = 1;
+            }
+            else if(a.serialNo < b.serialNo){
+                rst = -1;
+            }
+            return rst;
+        });
+    },
+    updateContent: function (billId, updateArr, contentTxt) {
+        let me = contentOprObj;
+        $.ajax({
+            type: 'post',
+            url: '',
+            dataType: 'json',
+            data: {billId: billId, updateArr: updateArr, contentTxt: contentTxt},
+            success: function (result) {
+                if(!result.error){
+                    me.showContentData(me.workBook.getSheet(0), me.setting, me.currentCache);//刷新jobSpread
+                    if(me.refreshColData){
+                       // mainSheet.setvalue(contentTxt); //刷新输出显示
+                        me.refreshColData = false;
+                    }
+                }
+            }
+        });
+    },
+    onContextmenuOpr: function () {//右键菜单
+        let me = contentOprObj;
+        $.contextMenu({
+            selector: '#jobSpread',
+            build: function($triggerElement, e){
+                //控制允许右键菜单在哪个位置出现
+                let clientX = e.originalEvent.clientX,
+                 clientY = e.originalEvent.clientY;
+                 let sheet = me.workBook.getSheet(0);
+                 let offset = $("#jobSpread").offset(),
+                 x = clientX - offset.left,
+                 y = clientY - offset.top;
+                 let target = sheet.hitTest(x, y);
+                if(target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){//在表格内
+                    sheet.setActiveCell(target.row, target.col);
+                    //控制按钮是否可用
+                    let insertDis = false, delDis = false, upDis = false, downDis = false;
+                    if(!me.currentCache ||target.row >= me.currentCache.length){//右键定位在有数据的行,删除键才显示可用
+                        delDis = true;
+                        downDis = true;
+                        upDis = true;
+                    }
+                    else{//有数据
+                        if(target.row === me.currentCache.length -1){//定位在最后一行,不可下移
+                            downDis = true;
+                        }
+                        if(target.row === 0){//定位在第一行,不可上移
+                            upDis = true;
+                        }
+                    }
+                    return {
+                        callback: function(){},
+                        items: {
+                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
+                            }},
+                            "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                                //删除
+                                let deleteObj = me.currentCache[target.row];
+                            }},
+                            "upMove": {name: "上移", disabled: upDis, icon: "fa-arrow-up", callback: function (key, opt) {
+
+                            }},
+                            "downMove": {name: "下移", disabled: downDis, icon: "fa-arrow-down", callback: function (key, opt) {
+
+                            }}
+                        }
+                    };
+                }
+                else{
+                    return false;
+                }
+            }
+        });
+    }
+};
+
+
+let characterOprObj = {
+    workBook: null,
+    currentCache: [],
+    setting: {
+        header: [
+            {headerName:"项目特征",headerWidth:160,dataCode:"character", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"特征值",headerWidth:160,dataCode:"eigenvalue", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"输出",headerWidth:80,dataCode:"isChecked", cellType:"checkBox", hAlign: "center", vAlign: "center"}
+        ]
+    },
+    buildSheet: function(container) {
+        let me = characterOprObj;
+        me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
+        me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+        me.onContextmenuOpr();
+        //me.workBook.getSheet(0).setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);
+        //me.workBook.getSheet(0).options.isProtected = true;
+        //sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+    },
+    //显示在itemSpread的数据
+    showCharacterData: function (sheet, setting, datas) {
+        sheetCommonObj.showData(sheet, setting, datas);
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = 0, len = datas.length; i < len; i++){
+            sheet.getCell(i, 0).locked(true);
+        }
+        sheet.resumePaint();
+        sheet.suspendEvent();
+    },
+    //显示到清单项目特征列的数据
+    getColData: function (itemsArr) {
+        let me = characterOprObj;
+        let rstStr = "", count = 0;
+        for(let i = 0, len = itemsArr.length; i < len; i++){
+            if(itemsArr[i].isChecked === true){
+                //获取选中的特征值
+                let eigenvalueStr = "";
+                let eigenvalue = itemsArr[i].eigenvalue;
+                for(let j = 0, vLen = eigenvalue.length; j < vLen; j++){
+                    if(eigenvalue[j].isSelected === true){
+                        eigenvalueStr += eigenvalue[j].value;
+                        break;
+                    }
+                }
+                count ++;
+                if(count === 1){
+                    rstStr += "“";
+                }
+                else{
+                    rstStr += " ";
+                }
+                rstStr += count + " " + itemsArr[i].content + ": " + eigenvalueStr + "\n";
+            }
+        }
+        if(rstStr.trim().length > 0){
+            let reg = /\n+$/g;
+            let newStr = rstStr.replace(reg, "”");
+            return newStr;
+        }
+        return null;
+    },
+    upMove: function (rowIdx) {
+        let me = characterOprObj;
+        let thisObj = me.currentCache[rowIdx],
+            preObj = me.currentCache[rowIdx - 1],
+            temp, characterTxt;
+        temp = thisObj.serialNo;
+        thisObj.serialNo = preObj.serialNo;
+        preObj.serialNo = temp;
+        contentOprObj.sortCache(me.currentCache);
+        if(thisObj.isChecked === true && preObj.isChecked === true){
+            me.refreshColData = true;
+            characterTxt = me.getColData(me.currentCache);
+        }
+        me.updateCharacter(me.currentCache, characterTxt);
+    },
+    downMove: function (rowIdx) {
+        let me = characterOprObj;
+        let thisObj = me.currentCache[rowIdx],
+            nextObj = me.currentCache[rowIdx + 1],
+            temp, characterTxt;
+        temp = thisObj.serialNo;
+        thisObj.serialNo = nextObj.serialNo;
+        nextObj.serialNo = temp;
+        contentOprObj.sortCache(me.currentCache);
+        if(thisObj.isChecked === true && nextObj.isChecked === true){
+            me.refreshColData = true;
+            characterTxt = me.getColData(me.currentCache);
+        }
+        me.updateCharacter(me.currentCache, characterTxt);
+    },
+    deleteContent: function (rowIdx) {
+        let me = characterOprObj, characterTxt;
+        let deleteObj = me.currentCache[rowIdx];
+        me.currentCache.splice(rowIdx, 1);
+        if(deleteObj.isChecked === true){//需要刷新显示
+            me.refreshColData = true;
+            characterTxt = me.getColData(me.currentCache);
+        }
+        me.updateCharacter(me.currentCache, characterTxt);
+    },
+    //只有空行时才可以输入,即是新增时用,新增的空行只有输入了值,才保存
+    onEditEnded: function (sender, args) {
+        let me = characterOprObj, characterTxt;
+        let preObj = me.currentCache.length > 0 ?  me.currentCache[me.currentCache.length - 1] : null;
+        if(args.editingText.toString().trim().length > 0){
+            let newObj = {content: args.editingText, isChecked: args.sheet.getValue(args.row, 1)};
+            newObj.serialNo = preObj ? preObj.serialNo + 1 : 1;//得到新增对象的排序号
+            me.currentCache.push(newObj);
+            if(newObj.isChecked === true){//可能编辑内容前就打勾
+                me.refreshColData = true;
+                characterTxt = me.getColData(me.currentCache);
+            }
+            me.updateCharacter(me.currentCache, characterTxt);
+        }
+    },
+    //复选框控制输出
+    onButtonClicked: function (sender, args) {
+        let me = characterOprObj, characterTxt;
+        if(args.sheet.isEditing()){
+            args.sheet.endEdit(true);
+        }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        if(me.currentCache.length > args.row){
+            me.currentCache[args.row].isChecked = isChecked;
+            me.refreshColData = true;
+            characterTxt = me.getColData(me.currentCache);
+            me.updateCharacter(me.currentCache, characterTxt);
+        }
+        //else的情况就是新增
+    },
+    updateCharacter: function (billId, updateArr, characterTxt) {
+        let me = characterOprObj;
+        $.ajax({
+            type: 'post',
+            url: '',
+            dataType: 'json',
+            data: {billId: billId, updateArr: updateArr, characterTxt: characterTxt},
+            success: function (result) {
+                if(!result.error){
+                   /* me.currentCache.sort(function (a, b) {
+                        let rst = 0;
+                        if(a.serialNo > b.serialNo){
+                            rst = 1;
+                        }
+                        else if(a.serialNo < b.serialNo){
+                            rst = -1;
+                        }
+                        return rst;
+                    });
+                    me.showCharacterData(me.workBook.getSheet(0), me.setting, me.currentCache);//刷新jobSpread
+                    if(me.refreshColData){
+                        //me.showColData(me.currentCache);//刷新输出显示
+                        me.refreshColData = false;
+                    }*/
+                }
+            }
+        });
+    },
+    onContextmenuOpr: function () {//右键菜单
+        let me = characterOprObj;
+        $.contextMenu({
+            selector: '#itemSpread',
+            build: function($triggerElement, e){
+                //控制允许右键菜单在哪个位置出现
+                let clientX = e.originalEvent.clientX,
+                    clientY = e.originalEvent.clientY;
+                let sheet = me.workBook.getSheet(0);
+                let offset = $("#itemSpread").offset(),
+                    x = clientX - offset.left,
+                    y = clientY - offset.top;
+                let target = sheet.hitTest(x, y);
+                if(target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){//在表格内
+                    sheet.setActiveCell(target.row, target.col);
+                    //控制按钮是否可用
+                    let insertDis = false, delDis = false, upDis = false, downDis = false;
+                    if(!me.currentCache ||target.row >= me.currentCache.length){//右键定位在有数据的行,删除键才显示可用
+                        delDis = true;
+                        downDis = true;
+                        upDis = true;
+                    }
+                    else{//有数据
+                        if(target.row === me.currentCache.length -1){//定位在最后一行,不可下移
+                            downDis = true;
+                        }
+                        if(target.row === 0){//定位在第一行,不可上移
+                            upDis = true;
+                        }
+                    }
+                    return {
+                        callback: function(){},
+                        items: {
+                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
+                            }},
+                            "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                                //删除
+                            }},
+                            "upMove": {name: "上移", disabled: upDis, icon: "fa-arrow-up", callback: function (key, opt) {
+
+                            }},
+                            "downMove": {name: "下移", disabled: downDis, icon: "fa-arrow-down", callback: function (key, opt) {
+
+                            }}
+                        }
+                    };
+                }
+                else{
+                    return false;
+                }
+            }
+        });
+    }
+};

+ 9 - 1
web/building_saas/main/js/views/main_tree_col.js

@@ -43,6 +43,14 @@ let MainTreeCol = {
             return MainTreeCol.readOnly.billsParent && MainTreeCol.readOnly.non_bills;
             return MainTreeCol.readOnly.billsParent && MainTreeCol.readOnly.non_bills;
         }
         }
     },
     },
+    cellType: {
+        unit: function () {
+            let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+            combo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
+                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
+            return combo;
+        }
+    },
     getEvent: function (eventName) {
     getEvent: function (eventName) {
         let names = eventName.split('.');
         let names = eventName.split('.');
         let event = this;
         let event = this;
@@ -77,4 +85,4 @@ let MainTreeCol = {
                 return '0.##';
                 return '0.##';
         }
         }
     }
     }
-}
+};

+ 16 - 1
web/building_saas/main/js/views/project_view.js

@@ -94,6 +94,10 @@ var projectObj = {
                     if (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object String]") {
                     if (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object String]") {
                         col.readOnly = MainTreeCol.getEvent(col.readOnly);
                         col.readOnly = MainTreeCol.getEvent(col.readOnly);
                     }
                     }
+                    if (col.data.cellType && Object.prototype.toString.apply(col.data.cellType) === "[object String]") {
+                        let getCellType = MainTreeCol.getEvent(col.data.cellType);
+                        col.data.cellType = getCellType();
+                    }
                     if (col.data.digit && Object.prototype.toString.apply(col.data.digit) === "[object String]") {
                     if (col.data.digit && Object.prototype.toString.apply(col.data.digit) === "[object String]") {
                         col.data.decimal = that.project.getDecimal(col.data.digit);
                         col.data.decimal = that.project.getDecimal(col.data.digit);
                         col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);
                         col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);
@@ -132,11 +136,22 @@ var projectObj = {
                             return false;
                             return false;
                         }
                         }
                     };
                     };
+                    let canDelete = function (node) {
+                        if (selected) {
+                            if (selected.sourceType === that.project.Bills.getSourceType()) {
+                                return !(selected.data.flagsIndex && selected.data.flagsIndex.fixed && selected.data.flagsIndex.fixed.flag > 0);
+                            } else {
+                                return true;
+                            }
+                        } else {
+                            return false;
+                        }
+                    };
                     setButtonValid(canUpLevel(selected), $('#upLevel'));
                     setButtonValid(canUpLevel(selected), $('#upLevel'));
                     setButtonValid(canDownLevel(selected), $('#downLevel'));
                     setButtonValid(canDownLevel(selected), $('#downLevel'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canUpMove(), $('#upMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canUpMove(), $('#upMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canDownMove(), $('#downMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canDownMove(), $('#downMove'));
-                    setButtonValid(selected, $('#delete'));
+                    setButtonValid(canDelete(selected), $('#delete'));
                 });
                 });
 
 
               /*  if(!projectObj.gljSpreed){
               /*  if(!projectObj.gljSpreed){

+ 27 - 1
web/building_saas/main/js/views/sub_view.js

@@ -1,11 +1,16 @@
 /**
 /**
  * Created by CSL on 2017-07-04.
  * Created by CSL on 2017-07-04.
  */
  */
-
+//modified by zhong on 2017-08-30
 // Tab panes 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
 // Tab panes 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
 var subSpread = sheetCommonObj.createSpread($("#subSpread")[0], 7);
 var subSpread = sheetCommonObj.createSpread($("#subSpread")[0], 7);
 subSpread.getSheet(4).name('JSCX');
 subSpread.getSheet(4).name('JSCX');
 
 
+//特征及内容spread,解决不能正确显示spread
+$("#jobSpread").width($("#subSpread").width() *0.5* 0.4);
+$("#itemSpread").width($("#subSpread").width() *0.5 - $("#jobSpread").width()-20);
+contentOprObj.buildSheet($("#jobSpread")[0]);
+characterOprObj.buildSheet($("#itemSpread")[0]);
 
 
 // 工料机
 // 工料机
 gljOprObj.initSheet(subSpread.getSheet(0));
 gljOprObj.initSheet(subSpread.getSheet(0));
@@ -27,6 +32,10 @@ SheetDataHelper.protectdSheet(subSpread.getSheet(3));
 
 
 
 
 $("#linkGLJ").click(function(){
 $("#linkGLJ").click(function(){
+/*    $('#subSpread').css("display", "");
+    $("#tzjnrCon").css("display", "none");*/
+    $("#tzjnrCon").hide();//控制显示subSpread,隐藏特征及内容spread
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(0);
     subSpread.setActiveSheetIndex(0);
     $.contextMenu( 'destroy', "#subSpread" );
     $.contextMenu( 'destroy', "#subSpread" );
     gljContextMenu.loadGLJSpreadContextMenu();
     gljContextMenu.loadGLJSpreadContextMenu();
@@ -35,6 +44,8 @@ $("#linkGLJ").click(function(){
 });
 });
 
 
 $("#linkFZDE").click(function(){
 $("#linkFZDE").click(function(){
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(1);
     subSpread.setActiveSheetIndex(1);
     $.contextMenu( 'destroy', "#subSpread" );
     $.contextMenu( 'destroy', "#subSpread" );
     // for test
     // for test
@@ -42,6 +53,8 @@ $("#linkFZDE").click(function(){
 });
 });
 
 
 $("#linkFZTJ").click(function(){
 $("#linkFZTJ").click(function(){
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(2);
     subSpread.setActiveSheetIndex(2);
     $.contextMenu( 'destroy', "#subSpread" );
     $.contextMenu( 'destroy', "#subSpread" );
     // for test
     // for test
@@ -49,6 +62,8 @@ $("#linkFZTJ").click(function(){
 });
 });
 
 
 $("#linkGCLMX").click(function(){
 $("#linkGCLMX").click(function(){
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(3);
     subSpread.setActiveSheetIndex(3);
     $.contextMenu( 'destroy', "#subSpread" );
     $.contextMenu( 'destroy', "#subSpread" );
     gljContextMenu.loadQuantityDetailMenu();
     gljContextMenu.loadQuantityDetailMenu();
@@ -57,6 +72,8 @@ $("#linkGCLMX").click(function(){
 });
 });
 
 
 $("#linkJSCX").click(function(){        // 计算程序
 $("#linkJSCX").click(function(){        // 计算程序
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(4);
     subSpread.setActiveSheetIndex(4);
     calcProgramObj.initSheet(subSpread.getSheet(4));
     calcProgramObj.initSheet(subSpread.getSheet(4));
     let sel = projectObj.mainController.tree.selected;
     let sel = projectObj.mainController.tree.selected;
@@ -69,17 +86,26 @@ $("#linkJSCX").click(function(){        // 计算程序
 });
 });
 
 
 $("#linkFXSM").click(function(){
 $("#linkFXSM").click(function(){
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(5);
     subSpread.setActiveSheetIndex(5);
     // for test
     // for test
     subSpread.getActiveSheet().setValue(0, 0, "分项说明");
     subSpread.getActiveSheet().setValue(0, 0, "分项说明");
 });
 });
 
 
 $("#linkDESM").click(function(){
 $("#linkDESM").click(function(){
+    $("#tzjnrCon").hide();
+    $("#subSpread").show();
     subSpread.setActiveSheetIndex(6);
     subSpread.setActiveSheetIndex(6);
     // for test
     // for test
     subSpread.getActiveSheet().setValue(0, 0, "定额说明");
     subSpread.getActiveSheet().setValue(0, 0, "定额说明");
 });
 });
 
 
+//特征及内容
+$("#linkTZJNR").click(function () {
+    $("#subSpread").hide();
+    $("#tzjnrCon").show();
+});
 function SubActiveSheetNameIs(sheetName){
 function SubActiveSheetNameIs(sheetName){
     let rst = subSpread.getActiveSheet().name() == sheetName;
     let rst = subSpread.getActiveSheet().name() == sheetName;
     return rst;
     return rst;