Browse Source

报表完善

TonyKang 7 years ago
parent
commit
3d5cd946dc

+ 1 - 1
modules/reports/controllers/rpt_controller.js

@@ -92,7 +92,7 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, option, cb) {
                     let maxPages = printCom.totalPages;
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                     if (pageRst) {
-                        //fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                        //fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
                         cb(null, pageRst);
                     } else {
                         cb('Have errors while on going...', null);

+ 39 - 17
modules/reports/rpt_component/jpc_bill_tab.js

@@ -1,8 +1,6 @@
 let JV = require('./jpc_value_define');
 let JpcFieldHelper = require('./helper/jpc_helper_field');
 let JpcBandHelper = require('./helper/jpc_helper_band');
-let JpcBand = require('./jpc_band');
-let JpcFlowTabHelper = require('./helper/jpc_helper_flow_tab');
 let JpcCommonHelper = require('./helper/jpc_helper_common');
 let JpcDiscreteHelper = require('./helper/jpc_helper_discrete');
 let JpcTextHelper = require('./helper/jpc_helper_text');
@@ -20,11 +18,24 @@ JpcBillTabSrv.prototype.createNew = function(){
         let me = this;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_BILL_INFO][JV.NODE_BILL_CONTENT][JV.PROP_BILL_FIELDS], null, me.disp_fields_idx);
     };
-    JpcBillTabResult.paging = function(rptTpl) {
-        let me = this, rst = 0;
-        let detail_fields = rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS];
-        if (detail_fields && detail_fields.length > 0) {
-            rst = detail_fields[0].length;
+    JpcBillTabResult.paging = function(rptTpl, dataObj) {
+        let rst = 0;
+        function getDataLength(fields_str) {
+            let dataFields = dataObj[fields_str];
+            if (dataFields && dataFields.length > 0) {
+                rst = dataFields[0].length;
+            }
+        }
+        if (rptTpl[JV.NODE_FIELD_MAP]) {
+            if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+                getDataLength(JV.DATA_DETAIL_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
+                getDataLength(JV.DATA_MASTER_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS]) {
+                getDataLength(JV.DATA_DISCRETE_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_PARAMS]) {
+                rst = 1;
+            }
         }
         return rst;
     };
@@ -36,31 +47,42 @@ JpcBillTabSrv.prototype.createNew = function(){
         //2. start to output detail-part
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
         //2.1 output content
-        tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus));
+        tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus, $CURRENT_RPT));
         //2.2 output discrete
         tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[JV.NODE_BILL_INFO][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, pageStatus, page - 1, 1, 0, $CURRENT_RPT));
-    }
-    JpcBillTabResult.outputContent = function(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus) {
+        for (let i = 0; i < tabRstLst.length; i++) {
+            rst = rst.concat(tabRstLst[i]);
+            tabRstLst[i] = null;
+        }
+        return rst;
+    };
+    JpcBillTabResult.outputContent = function(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus, $CURRENT_RPT) {
         let me = this, rst = [];
         let tab = rptTpl[JV.NODE_BILL_INFO][JV.NODE_BILL_CONTENT];
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
-            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
+            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 let tab_fields = tab[JV.PROP_BILL_FIELDS];
-                let data_details = dataObj[JV.DATA_MASTER_DATA];
+                let data_details = null;
+                if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+                    data_details = dataObj[JV.DATA_DETAIL_DATA];
+                } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
+                    data_details = dataObj[JV.DATA_MASTER_DATA];
+                }
                 for (let i = 0; i < tab_fields.length; i++) {
                     let tab_field = tab_fields[i];
                     let data_field = null;
-                    if (me.disp_fields_idx[i] != JV.BLANK_FIELD_INDEX) {
+                    if (me.disp_fields_idx.length > i && me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
                         data_field = data_details[me.disp_fields_idx[i]];
                     } else {
-                        data_field = JE.F(tab_field[JV.PROP_FIELD_ID]);
+                        data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
                         if (data_field) {
                             data_field = data_field[JV.PROP_AD_HOC_DATA];
                         }
                     }
                     if (!(tab_field[JV.PROP_HIDDEN])) {
-                        let cellItem = JpcCommonOutputHelper.createCommonOutput(tab_field, JpcFieldHelper.getValue(data_field, page - 1), controls);
+                        let val = JpcFieldHelper.getValue(data_field, page - 1);
+                        let cellItem = JpcCommonOutputHelper.createCommonOutput(tab_field, val, controls);
                         cellItem[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, 1, 0, 1, 0, 1, 0, true, false);
                         rst.push(cellItem);
                     }
@@ -79,8 +101,8 @@ JpcBillTabSrv.prototype.createNew = function(){
             }
         }
         return rst;
-    }
+    };
     return JpcBillTabResult;
-}
+};
 
 module.exports = new JpcBillTabSrv();

+ 19 - 13
modules/reports/rpt_component/jpc_data.js

@@ -10,17 +10,21 @@ let JpcData = {
             let private_analyse = function(MASTER_FIELD_STR, DETAIL_FIELD_STR, MASTER_DATA_STR, DETAIL_DATA_STR, dataSeqArr) {
                 //1. get ID fields
                 let masterIDs = [];
-                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR].length; i++) {
-                    let mstFieldObj = rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR][i];
-                    if (jpc_common_helper.getBoolean(mstFieldObj[JV.PROP_IS_ID])) {
-                        masterIDs.push({"idx": i, "seq": mstFieldObj[JV.PROP_ID_SEQ]});
+                if (rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR]) {
+                    for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR].length; i++) {
+                        let mstFieldObj = rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR][i];
+                        if (jpc_common_helper.getBoolean(mstFieldObj[JV.PROP_IS_ID])) {
+                            masterIDs.push({"idx": i, "seq": mstFieldObj[JV.PROP_ID_SEQ]});
+                        }
                     }
                 }
                 let detailIDs = [];
-                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR].length; i++) {
-                    let dtlFieldObj = rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR][i];
-                    if (jpc_common_helper.getBoolean(dtlFieldObj[JV.PROP_IS_ID])) {
-                        detailIDs.push({"idx": i, "seq": dtlFieldObj[JV.PROP_ID_SEQ]});
+                if (rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR]) {
+                    for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR].length; i++) {
+                        let dtlFieldObj = rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR][i];
+                        if (jpc_common_helper.getBoolean(dtlFieldObj[JV.PROP_IS_ID])) {
+                            detailIDs.push({"idx": i, "seq": dtlFieldObj[JV.PROP_ID_SEQ]});
+                        }
                     }
                 }
                 //2. sort the ID fields
@@ -84,11 +88,13 @@ let JpcData = {
                         }
                     }
                 } else { //if no master data
-                    let field = dataObj[DETAIL_DATA_STR][0];
-                    //dataSeqArr = [[]];
-                    dataSeqArr.push([]);
-                    for (let i = 0; i < field.length; i++) {
-                        dataSeqArr[0].push(i);
+                    if (dataObj && dataObj[DETAIL_DATA_STR] && dataObj[DETAIL_DATA_STR].length > 0) {
+                        //may be bill type report which may only have discrete fields!
+                        let field = dataObj[DETAIL_DATA_STR][0];
+                        dataSeqArr.push([]);
+                        for (let i = 0; i < field.length; i++) {
+                            dataSeqArr[0].push(i);
+                        }
                     }
                 }
             };

+ 5 - 2
modules/reports/rpt_component/jpc_ex.js

@@ -125,6 +125,9 @@ JpcExSrv.prototype.createNew = function(){
                 me.flowTabEx.sorting(rptTpl, dataObj, dataHelper.exDataSeq.slice(0));
             }
         }
+        if (me.billTab) {
+            me.billTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
+        }
         if (me.crossTab) {
             me.crossTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
         }
@@ -155,7 +158,7 @@ JpcExSrv.prototype.createNew = function(){
             //me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, dftPagingOption);
             me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, JV.PAGING_OPTION_NORMAL); //infinity对交叉表来说无意义
         } else if (me.billTab) {
-            me.totalPages = me.billTab.paging();
+            me.totalPages = me.billTab.paging(rptTpl, dataObj);
         }
     };
     JpcResult.executeFormulas = function(runType, $CURRENT_TEMPLATE, $CURRENT_DATA, $CURRENT_RPT) {
@@ -244,7 +247,7 @@ JpcExSrv.prototype.createNew = function(){
             } else if (me.crossTab) {
                 rst[JV.PROP_CELLS] = me.crossTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             } else if (me.billTab) {
-                //
+                rst[JV.PROP_CELLS] = me.billTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             }
             if (!(me.flowTab && me.flowTab.paging_option === JV.PAGING_OPTION_INFINITY)) {
                 let pageMergeBorder = getPageMergeBorder();

+ 12 - 5
modules/reports/util/rpt_construct_data_util.js

@@ -143,6 +143,9 @@ class Rpt_Data_Extractor {
         pri_setup_filter(JV.NODE_DETAIL_FIELDS);
         pri_setup_filter(JV.NODE_MASTER_FIELDS_EX);
         pri_setup_filter(JV.NODE_DETAIL_FIELDS_EX);
+        if (rst.length === 0) {
+            rst.push(projectConst.RATION_ASS);
+        }
         return rst;
     };
 
@@ -263,7 +266,7 @@ function summaryData(sourceData, handleCfg, prjData){
     }
     delete sourceData.data;
     sourceData.data = rstArr;
-    // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sumRst.js");
+    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sumRst.js");
 }
 
 function filterData(sourceData, handleCfg, prjData) {
@@ -331,7 +334,7 @@ function filterData(sourceData, handleCfg, prjData) {
     }
     delete sourceData.data;
     sourceData.data = rstArr;
-    // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.js");
+    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.js");
 }
 
 function adjustData(sourceData, adjustCfg) {
@@ -527,13 +530,13 @@ function sortData(sourceData, sortCfg, prjData) {
             treeUtil.getFlatArray(rst, destArr);
             delete sourceData.data;
             sourceData.data = destArr;
-            // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.js");
+            // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.js");
             break;
         case "normal":
             private_normal_sort(tempRstArr, sortCfg[JV.PROP_SORT_KEYS]);
             delete sourceData.data;
             sourceData.data = tempRstArr;
-            // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/normalSortedRst.js");
+            // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/normalSortedRst.js");
             break;
         case "accord_to_parent":
             let pcKey = sortCfg[JV.PROP_PARENT_CHILD_SORT_KEY];
@@ -625,7 +628,11 @@ function ext_mainGetPropety(propKey) {
     let dtObj = parentObj["myOwnRawDataObj"];
     if (propKey && dtObj) {
         if (dtObj.hasOwnProperty("property")) {
-            rst.push(dtObj["property"][propKey]);
+            if (!dtObj["property"][propKey] && dtObj[propKey]) {
+                rst.push(dtObj[propKey]);
+            } else {
+                rst.push(dtObj["property"][propKey]);
+            }
         } else  {
             rst.push(dtObj[propKey]);
         }

+ 7 - 2
modules/reports/util/rpt_excel_util.js

@@ -158,6 +158,9 @@ function writeStyles(stylesObj){
         if (strUtil.convertStrToBoolean(font[JV.FONT_PROPS[3]])) {
             rst.push('<b/>');
         }
+        if (strUtil.convertStrToBoolean(font[JV.FONT_PROPS[5]])) {
+            rst.push('<u/>');
+        }
         rst.push('<sz val="' + font.size + '"/>');
         rst.push('<color indexed="' + font.colorIdx + '"/>');
         rst.push('<name val="' + font[JV.FONT_PROPS[0]] + '"/>');
@@ -420,7 +423,8 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         for (let i = 0; i < stylesObj.fonts.length; i++) {
             let font = stylesObj.fonts[i];
             if (sheetFont) {
-                if (font[JV.FONT_PROPS[0]] === sheetFont[JV.FONT_PROPS[0]] && font.size === Math.round(sheetFont[JV.FONT_PROPS[1]] * 3 / 4) && font[JV.FONT_PROPS[3]] == sheetFont[JV.FONT_PROPS[3]]) {
+                if (font[JV.FONT_PROPS[0]] === sheetFont[JV.FONT_PROPS[0]] && font.size === Math.round(sheetFont[JV.FONT_PROPS[1]] * 3 / 4)
+                    && font[JV.FONT_PROPS[3]] === sheetFont[JV.FONT_PROPS[3]] && font[JV.FONT_PROPS[5]] === sheetFont[JV.FONT_PROPS[5]]) {
                     hasFont = true;
                     rst = i;
                     break;
@@ -436,6 +440,7 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
             font.charset = 134;
             font.colorIdx = "8";
             font[JV.FONT_PROPS[3]] = sheetFont[JV.FONT_PROPS[3]]; //font bold
+            font[JV.FONT_PROPS[5]] = sheetFont[JV.FONT_PROPS[5]]; //font underline
             stylesObj.fonts.push(font);
             rst = stylesObj.fonts.length - 1;
         }
@@ -983,7 +988,7 @@ module.exports = {
             }
             //3. everything is ok, then call me
             me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, callback);
-            fsUtil.wirteObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
+            fsUtil.writeObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
         } catch (e) {
             console.log(e);
         }

+ 1 - 1
public/fsUtil.js

@@ -25,7 +25,7 @@ module.exports = {
             });
         }
     },
-    wirteObjToFile: function(obj, filePath) {
+    writeObjToFile: function(obj, filePath) {
         if (obj) {
             let arr = [];
             arr.push(JSON.stringify(obj));

+ 4 - 1
public/web/rpt_value_define.js

@@ -136,6 +136,7 @@ const JV = {
     PROP_CALCULATION: "CalculationType",
     PROP_H_CALCULATION: "H_CalculationType",
     PROP_V_CALCULATION: "V_CalculationType",
+    PROP_FIT_AREA: "isFitArea",
 
     IDX_LEFT: 0,
     IDX_TOP: 1,
@@ -236,7 +237,7 @@ const JV = {
     SIZE_16K: [7.75, 10.75],
     SIZE_EXECUTIVE: [7.25, 10.5],
 
-    OUTPUT_OFFSET: [2,1,2,3],
+    OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,
     OFFSET_IDX_TOP: 2,
@@ -265,6 +266,8 @@ const JV = {
 
     VERTICAL_ANGLE: "90",
     ANTI_VERTICAL_ANGLE: "-90",
+    VERTICAL_ANGLE_INT: 90,
+    ANTI_VERTICAL_ANGLE_INT: -90,
 
     LAST_DEF: ""
 };

+ 116 - 0
test/unit/reports/test_cover_01.js

@@ -0,0 +1,116 @@
+/**
+ * Created by Tony on 2017/11/21.
+ */
+
+let test = require('tape');
+import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
+import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let mongoose = require("mongoose");
+let fileUtils = require("../../../modules/common/fileUtils");
+let path = require('path');
+let dbm = require("../../../config/db/db_manager");
+let rpt_cfg = require('./rpt_cfg');
+dbm.connect();
+let consts = require('../../../modules/main/models/project_consts');
+let projectConsts = consts.projectConst;
+fileUtils.getGlobbedFiles('../../../modules/complementary_glj_lib/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+fileUtils.getGlobbedFiles('../../../modules/ration_glj/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+//引入报表模块
+fileUtils.getGlobbedFiles('../../../modules/reports/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+})
+
+//暂时引入其它模块的model
+require('../../../modules/fee_rates/models/fee_rates');
+// 引入人工系数模块
+require('../../../modules/main/models/labour_coe_model');
+require('../../../modules/main/models/calc_program_model');
+
+let fsUtil = require("../../../public/fsUtil");
+
+let prjMdl = require('../../../modules/pm/models/project_model');
+let projectDataMdl = require('../../../modules/main/models/project');
+let demoPrjId = - 1;
+let demoRptId = 223, pagesize = "A4";
+
+let userId_Leng = 1142; //小冷User Id
+// demoPrjId = 720; //QA: DW3
+demoPrjId = 838; //QA:
+/*/
+ let userId_Dft = userId_Leng;
+ /*/
+let userId_Dft = 76075;
+//*/
+
+let rptTplFacade = require("../../../modules/reports/facade/rpt_template_facade");
+let rptTplDataFacade = require("../../../modules/reports/facade/rpt_tpl_data_facade");
+
+import rptDataExtractor from "../../../modules/reports/util/rpt_construct_data_util";
+
+let fs = require('fs');
+//设置Date Format函数
+fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+    eval(data);
+});
+
+//*
+test('测试 - 打开模板: 封-1 ', function (t) {
+    rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
+        let rptDataUtil = new rptDataExtractor();
+        rptDataUtil.initialize(rptTpl._doc);
+        let filter = rptDataUtil.getDataRequestFilter();
+        // console.log(filter);
+        //正常应该根据报表模板定义的数据类型来请求数据
+        rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
+            if (!err) {
+                try {
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    let tplData = rptDataUtil.assembleData(rawDataObj);
+                    //build the report
+                    let printCom = JpcEx.createNew();
+                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                    let defProperties = rpt_cfg;
+                    let dftOption = JV.PAGING_OPTION_NORMAL;
+                    printCom.initialize(rptTpl);
+                    printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
+                    let maxPages = printCom.totalPages;
+                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                    if (pageRst) {
+                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                    } else {
+                        console.log("oh! no pages were created!");
+                    }
+                } catch (ex) {
+                    console.log(ex);
+                    t.pass('pass with exception!');
+                    t.end();
+                }
+
+                t.pass('pass succeeded!');
+                t.end();
+            } else {
+                console.log(msg);
+                t.pass('pass with error!');
+                t.end();
+            }
+        })
+    });
+});
+//*/
+
+test('close the connection', function (t) {
+    setTimeout(function () {
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 8000);
+    // mongoose.disconnect();
+    // t.pass('closing db connection');
+    // t.end();
+});

+ 6 - 6
test/unit/reports/test_tpl_09_1.js

@@ -62,7 +62,7 @@ fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.j
 test('测试 - 获取project数据: ', function (t) {
     projectDataMdl.getData(demoPrjId, function (err, message, result) {
         if (!err) {
-            fsUtil.wirteObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.js");
+            fsUtil.writeObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.js");
             t.pass('pass succeeded!');
             t.end();
         } else {
@@ -91,8 +91,8 @@ test('测试 - 获取project部分数据: ', function (t) {
                     //     newData.push(JSON.stringify(item));
                     // }
                     // fsUtil.writeArrayToFile(newData, "D:/GitHome/ConstructionCost/tmp/getProjectData_partial.js");
-                    // fsUtil.wirteObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.js");
-                    fsUtil.wirteObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.js");
+                    // fsUtil.writeObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.js");
+                    fsUtil.writeObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.js");
                     t.pass('pass succeeded!');
                     t.end();
                 } else {
@@ -121,7 +121,7 @@ test('测试 - 测试模板啦: ', function (t) {
             if (!err) {
                 try {
                     let tplData = rptDataUtil.assembleData(rawDataObj);
-                    // fsUtil.wirteObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();
                     rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
@@ -134,7 +134,7 @@ test('测试 - 测试模板啦: ', function (t) {
                     if (pageRst) {
                         // fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
                     } else {
-                        console.log("oh! no pages were created!")
+                        console.log("oh! no pages were created!");
                     }
                 } catch (ex) {
                     console.log(ex);
@@ -180,7 +180,7 @@ test('测试 - 显示保存小数位数问题: ', function (t) {
     rpt_decimal_mdl.find({}).then(function (rst) {
         //console.log(rst);
         if (rst.length > 0) {
-            fsUtil.wirteObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
+            fsUtil.writeObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
         }
         t.pass('pass get decimal ok!');
         t.end();

+ 78 - 23
web/building_saas/report/js/jpc_output.js

@@ -17,26 +17,26 @@ let JpcCanvasOutput = {
 
         function private_setupAreaH(area, type, fontAngle, dftFontHeight, outputPoint) {
             let lType = type;
-            if (type != "left" && type != "right" && type != "center") lType = "left";
+            if (type !== "left" && type !== "right" && type !== "center") lType = "left";
             switch (lType) {
                 case "left":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
                     } else outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
                     ctx.textAlign="start";
                     break;
                 case "right":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         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) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT || fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
                     } else outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2;
                     ctx.textAlign="center";
@@ -45,26 +45,26 @@ let JpcCanvasOutput = {
         }
         function private_setupAreaV(area, type, fontAngle, dftFontHeight, outputPoint) {
             let lType = type;
-            if (type != "top" && type != "bottom" && type != "center") lType = "top";
+            if (type !== "top" && type !== "bottom" && type !== "center") lType = "top";
             switch (lType) {
                 case "top":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
                     } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
                     break;
                 case "bottom":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
                     } else outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
                     break;
                 case "center":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
                     } else outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
                     break;
@@ -74,31 +74,75 @@ let JpcCanvasOutput = {
             let dftFontHeight = 12;
             let output = [];
             if (font) {
-                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                dftFontHeight = parseFloat(font[JV.FONT_PROPS[1]]);
                 let dftOthers = "";
                 let dftFontBold = font[JV.FONT_PROPS[3]];
-                if (dftFontBold && dftFontBold == 'T') {
+                if (dftFontBold && dftFontBold === 'T') {
                     dftOthers = "bold " + dftOthers ;
                 }
                 let dftFontItalic = font[JV.FONT_PROPS[4]];
-                if (dftFontItalic && dftFontItalic == 'T') {
+                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);
+                private_setupAreaH(area, control.Horizon, parseInt(font.FontAngle), dftFontHeight, output);
+                private_setupAreaV(area, control.Vertical, parseInt(font.FontAngle), dftFontHeight, output);
             } else {
-                private_setupAreaH(area, "left", font.FontAngle, dftFontHeight, output);
-                private_setupAreaV(area, "bottom", font.FontAngle, dftFontHeight, output);
+                private_setupAreaH(area, "left", parseInt(font.FontAngle), dftFontHeight, output);
+                private_setupAreaV(area, "bottom", parseInt(font.FontAngle), dftFontHeight, output);
             }
             let w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-            if (font.FontAngle != "0") {
+            if ( parseInt(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];
             }
+
+            function private_drawUnderline() {
+                //A. 暂不支持角度; B. 坐标已经translate
+                //1. 计算下划线的相关坐标
+                let width = ctx.measureText(val).width;
+                let height = dftFontHeight;
+                // let startX = area[JV.IDX_LEFT], startY = area[JV.IDX_TOP], endX = area[JV.IDX_RIGHT], endY = area[JV.IDX_BOTTOM];
+                let startX = 0, startY = 0, endX = width, endY = startY;
+                if (control.Horizon === "left") {
+                    // 无变化;
+                } else if (control.Horizon === "right") {
+                    startX = Math.round(startX - width);
+                } else {
+                    startX = Math.round(startX - width / 2);
+                }
+                endX = Math.round(startX + width);
+
+                if (control.Vertical === "top") {
+                    startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                } else if (control.Vertical === "bottom") {
+                    // startY = Math.round(startY);
+                    startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                } else {
+                    startY = Math.round(height / 2) - JV.OUTPUT_OFFSET[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                    // startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                }
+                endY = Math.round(startY);
+                //2. 画线
+                // ctx.save();
+                if ( output[1] !== Math.round(output[1])) {
+                    ctx.translate(0,0.5);
+                }
+                ctx.beginPath();
+                ctx.moveTo(startX, startY);
+                ctx.lineWidth = 1;
+                ctx.strokeStyle = "BLACK";
+                ctx.lineTo(endX, endY);
+                ctx.stroke();
+                // ctx.restore();
+            }
+
             ctx.save();
             ctx.translate(output[0], output[1]);
+            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                private_drawUnderline();
+            }
             if (font.FontAngle === JV.VERTICAL_ANGLE) {
                 ctx.rotate(Math.PI/2);
             } else if (font.FontAngle === JV.ANTI_VERTICAL_ANGLE) {
@@ -121,8 +165,19 @@ let JpcCanvasOutput = {
         function private_drawCellText(cell, fonts, controls) {
             if (cell[JV.PROP_VALUE]) {
                 let values = ("" + cell[JV.PROP_VALUE]).split('|');
-                let font = fonts[cell[JV.PROP_FONT]];
-                let control = controls[cell[JV.PROP_CONTROL]];
+                let font = null;
+                if (typeof cell[JV.PROP_FONT] === "string") {
+                    font = fonts[cell[JV.PROP_FONT]];
+                } else {
+                    font = cell[JV.PROP_FONT];
+                }
+                //let control = controls[cell[JV.PROP_CONTROL]];
+                let control = null;
+                if (typeof cell[JV.PROP_CONTROL] === "string") {
+                    control = controls[cell[JV.PROP_CONTROL]];
+                } else {
+                    control = cell[JV.PROP_CONTROL];
+                }
                 if (control.ShowZero === "F") {
                     if (parseFloat(cell[JV.PROP_VALUE]) === 0.0) {
                         values = [""];

+ 3 - 1
web/building_saas/report/js/jpc_output_value_define.js

@@ -39,12 +39,14 @@ let JV = {
     PROP_COLOR: "Color",
     FONT_PROPS: ["Name", "FontHeight", "FontColor", "FontBold", "FontItalic", "FontUnderline", "FontStrikeOut", "FontAngle"],
 
-    OUTPUT_OFFSET: [2,1,2,3],
+    OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,
     OFFSET_IDX_TOP: 2,
     OFFSET_IDX_BOTTOM: 3,
 
+    VERTICAL_ANGLE_INT: 90,
+    ANTI_VERTICAL_ANGLE_INT: -90,
     VERTICAL_ANGLE: "90",
     ANTI_VERTICAL_ANGLE: "-90"
 };

+ 2 - 2
web/building_saas/report/js/rpt_main.js

@@ -80,10 +80,10 @@ let zTreeOprObj = {
                         me.currentPage = 1;
                         if (pageSize === "A4") {
                             canvas.width = 1200;
-                            canvas.height = 900;
+                            canvas.height = 1200;
                         } else if (pageSize === "A3") {
                             canvas.width = 1880;
-                            canvas.height = 1200;
+                            canvas.height = 1880;
                         }
                         me.showPage(0, canvas);
                     }