Browse Source

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

zhongzewei 7 years ago
parent
commit
7c5da890f8
31 changed files with 410 additions and 182 deletions
  1. 1 0
      config/gulpConfig.js
  2. 5 1
      modules/all_models/bills_template.js
  3. 4 0
      modules/all_models/engineering_lib.js
  4. 4 0
      modules/all_models/proj_setting.js
  5. 4 1
      modules/all_models/tem_bills.js
  6. 43 42
      modules/glj/models/glj_list_model.js
  7. 1 1
      modules/glj/models/unit_price_model.js
  8. 13 0
      modules/main/controllers/project_controller.js
  9. 19 1
      modules/main/facade/project_facade.js
  10. 1 0
      modules/main/routes/project_route.js
  11. 1 1
      modules/pm/controllers/new_proj_controller.js
  12. 1 1
      modules/pm/facade/pm_facade.js
  13. 1 1
      modules/pm/models/templates/bills_template_model.js
  14. 1 1
      modules/ration_glj/facade/ration_glj_facade.js
  15. 5 1
      public/web/sheet/sheet_common.js
  16. 1 1
      public/web/sheet/sheet_data_helper.js
  17. 0 0
      test/unit/reports/pdfkit_test.js
  18. 9 1
      web/building_saas/css/custom.css
  19. 8 1
      web/building_saas/main/html/calc_program_manage.html
  20. 2 1
      web/building_saas/main/html/main.html
  21. 1 9
      web/building_saas/main/html/tender_price.html
  22. 4 2
      web/building_saas/main/js/models/calc_program.js
  23. 4 0
      web/building_saas/main/js/models/project.js
  24. 1 1
      web/building_saas/main/js/models/ration.js
  25. 36 0
      web/building_saas/main/js/views/glj_col.js
  26. 0 2
      web/building_saas/main/js/views/glj_view.js
  27. 7 0
      web/building_saas/main/js/views/main_tree_col.js
  28. 9 9
      web/building_saas/main/js/views/project_glj_view.js
  29. 95 27
      web/building_saas/main/js/views/tender_price_view.js
  30. 22 41
      web/building_saas/report/html/rpt_print.html
  31. 107 36
      web/building_saas/report/js/rpt_print.js

+ 1 - 0
config/gulpConfig.js

@@ -101,6 +101,7 @@ module.exports = {
         'public/web/tree_sheet/tree_sheet_controller.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
         'public/web/sheet/sheet_data_helper.js',
+        'web/building_saas/main/js/views/glj_col.js',
         'web/building_saas/main/js/views/main_tree_col.js',
         'web/building_saas/main/js/views/project_info.js',
         'web/building_saas/main/js/views/project_view.js',

+ 5 - 1
modules/all_models/bills_template.js

@@ -13,6 +13,10 @@ var BillsTemplateSchema = new Schema({
     name: String,
     unit: String,
     deleteInfo: deleteSchema,
-    tempType: Number
+    tempType: Number,
+    //计算基数
+    calcBase: String,
+    //费率ID
+    feeRateID:Number
 });
 //mongoose.model('temp_bills', BillsTemplateSchema);  之后删除

+ 4 - 0
modules/all_models/engineering_lib.js

@@ -40,6 +40,10 @@ let modelSchema = {
     fee_lib: {
         type: Schema.Types.Mixed,
         default: []
+    },
+    //设置人材机显示列
+    glj_col:{
+        showAdjustPrice:Boolean//是否显示调整价列
     }
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 4 - 0
modules/all_models/proj_setting.js

@@ -11,6 +11,10 @@ let projSettingSchema = {
     main_tree_col: {
         type: Schema.Types.Mixed,
         default: {}
+    },
+    //设置人材机显示列
+    glj_col:{
+        showAdjustPrice:Boolean//是否显示调整价列
     }
 };
 mongoose.model(collectionName, new Schema(projSettingSchema, {versionKey: false, collection: collectionName}));

+ 4 - 1
modules/all_models/tem_bills.js

@@ -30,7 +30,10 @@ const BillsTemplateSchema = {
     // 工程专业
     engineering: Number,
     type:Number,
-    calcBase: String
+    //计算基数
+    calcBase: String,
+    //费率ID
+    feeRateID:Number
 };
 
 mongoose.model('temp_bills', BillsTemplateSchema, 'temp_bills');

+ 43 - 42
modules/glj/models/glj_list_model.js

@@ -250,9 +250,19 @@ class GLJListModel extends BaseModel {
             };
             let projectGljData = await this.findDataByCondition(condition);
             let isAddProjectGLJ = false;
+
+            // 获取标段对应的单价文件id
+            let unitPriceFileId = unitFileId?unitFileId:await ProjectModel.getUnitPriceFileId(data.project_id);
+            if (unitPriceFileId <= 0) {
+                throw '没有对应的单价文件';
+            }
+
+            let unitPriceModel = new UnitPriceModel();
+
+            // 新增单条记录 (两个操作本来应该是事务操作,然而mongodb事务支持比较弱,就当作是都可以顺利执行)
+
             // 如果找不到数据则新增
             if (!projectGljData) {
-                // 新增单条记录 (两个操作本来应该是事务操作,然而mongodb事务支持比较弱,就当作是都可以顺利执行)
                 let gljInsertData = await this.add(data);
                 if (!gljInsertData) {
                     throw '新增项目工料机失败!';
@@ -261,14 +271,7 @@ class GLJListModel extends BaseModel {
                 projectGljData = gljInsertData;
             }
 
-            // 获取标段对应的单价文件id
-
-            let unitPriceFileId = unitFileId?unitFileId:await ProjectModel.getUnitPriceFileId(data.project_id);
-            if (unitPriceFileId <= 0) {
-                throw '没有对应的单价文件';
-            }
             let CompositionGLJ=[];
-            let unitPriceModel = new UnitPriceModel();
             // 判断类型,如果是混凝土、砂浆、配合比或者主材则查找对应的组成物(前提是没有对应的项目工料机数据)
             if(this.ownCompositionTypes.indexOf(data.type)!=-1) {
                 //如果是新增
@@ -288,7 +291,6 @@ class GLJListModel extends BaseModel {
                 }
             }
             projectGljData.subList=CompositionGLJ;
-
             // 新增单价文件
             let [unitPriceInsertData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
 
@@ -573,36 +575,31 @@ class GLJListModel extends BaseModel {
                 throw '组成物插入单价数据失败!';
             }
         }
-        let pglj_length = projectGljList instanceof Array ? projectGljList.length:Object.getOwnPropertyNames(projectGljList).length;
-        // 如果已经存在则后续操作停止
-        if(pglj_length === compositionGljList.length) {
-            return
-        }
+        let unitPriceModel = new UnitPriceModel();
+        let unitPriceList = await unitPriceModel.model.find({unit_price_file_id:unitPriceFileId});//查找按文件id查找单价文件数据,用来判断单价文件信息是否已存在
 
         // 整理插入的数据
         let gljInsertData = [];
         let unitPriceInsertData = [];
         for(let tmp of compositionGljList) {
             let key = this.getIndex(tmp,['code','name','specs','unit','gljType']);
-            if (projectGljList[key] !== undefined) {
-                continue;
+            if (projectGljList[key] === undefined) {
+                // 项目工料机插入的数据
+                let gljData = {
+                    glj_id: tmp.ID,
+                    project_id: projectId,
+                    code: tmp.code,
+                    name: tmp.name,
+                    specs: tmp.specs,
+                    unit: tmp.unit === undefined ? '' : tmp.unit,
+                    type: tmp.gljType,
+                    adjCoe:tmp.adjCoe,
+                    original_code:tmp.code,
+                    materialType: tmp.materialType,   //三材类别
+                    materialCoe: tmp.materialCoe
+                };
+                gljInsertData.push(gljData);
             }
-            // 项目工料机插入的数据
-            let gljData = {
-                glj_id: tmp.ID,
-                project_id: projectId,
-                code: tmp.code,
-                name: tmp.name,
-                specs: tmp.specs,
-                unit: tmp.unit === undefined ? '' : tmp.unit,
-                type: tmp.gljType,
-                adjCoe:tmp.adjCoe,
-                original_code:tmp.code,
-                materialType: tmp.materialType,   //三材类别
-                materialCoe: tmp.materialCoe
-            };
-            gljInsertData.push(gljData);
-
             let basePrice = scMathUtil.roundTo(tmp.basePrice,-6);
             // 单价文件插入的数据
             let unitPriceData = {
@@ -622,19 +619,17 @@ class GLJListModel extends BaseModel {
             if(tmp.from=='cpt'){
                 unitPriceData.is_add = 1;
             }
-            unitPriceInsertData.push(unitPriceData);
+           if(!unitPriceModel.isPropertyInclude(unitPriceList,['code','name','specs','unit','type'],unitPriceData)){
+               unitPriceInsertData.push(unitPriceData);
+           }
         }
         // 整理完后开始插入数据
-        let addResult = await this.add(gljInsertData);
-        if (!addResult) {
-            throw '组成物插入项目工料机失败!';
-        }
+
         // 插入单价数据表
-        let unitPriceModel = new UnitPriceModel();
-        let addUnitPriceResult = await unitPriceModel.add(unitPriceInsertData);
-        if (!addUnitPriceResult) {
-            throw '组成物插入单价数据失败!';
-        }
+        if(unitPriceInsertData.length >0) await unitPriceModel.add(unitPriceInsertData);
+       //插入项目工料机
+        if(gljInsertData.length > 0) await this.add(gljInsertData);
+
 
         return
     }
@@ -719,6 +714,12 @@ class GLJListModel extends BaseModel {
 
     async getCompositionGLJByData(glj,unitPriceFileId){
         let [gljData,mixRatioData,unitPriceData] = await this.getCompositionListByGLJ(glj,unitPriceFileId);
+        let priceNum = unitPriceData?Object.getOwnPropertyNames(unitPriceData).length:0;
+        let mixNum = mixRatioData?Object.getOwnPropertyNames(mixRatioData).length:0;
+        if(priceNum !==mixNum){//检查组成物数据是否一致
+            console.log("组成物数据有误,组成物单价文件个数:"+priceNum+",    组成物个数:"+mixNum);
+            return []
+        }
         gljData = this.combineData(gljData, unitPriceData, [], mixRatioData);
         return gljData;
     }

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

@@ -184,7 +184,7 @@ class UnitPriceModel extends BaseModel {
         }
         if(pops instanceof  Array){
             for(let p of pops){
-                if(obj[p]){
+                if(obj[p]!==undefined && obj[p]!==undefined!=null){
                     condition[p]=obj[p]
                 }
             }

+ 13 - 0
modules/main/controllers/project_controller.js

@@ -123,5 +123,18 @@ module.exports = {
             result.message = err.message;
         }
         res.json(result);
+    },
+    saveProperty: function(req, res){
+        let result = {error: 0, message: '', data: null};
+        let data = JSON.parse(req.body.data);
+        project_facade.saveProperty(data, function (err, data) {
+            if (err == ''){
+                result.data = data;
+            }else{
+                result.error = 1;
+                result.message = err;
+            }
+            res.json(result);
+        })
     }
 };

+ 19 - 1
modules/main/facade/project_facade.js

@@ -2,6 +2,7 @@
  * Created by zhang on 2018/1/26.
  */
 let mongoose = require('mongoose');
+let logger = require("../../../logs/log_helper").logger;
 let  projectsModel = mongoose.model('projects');
 let async_n = require("async");
 let _ = require('lodash');
@@ -19,7 +20,8 @@ module.exports = {
     markUpdateProject:markUpdateProject,
     removeProjectMark:removeProjectMark,
     updateNodes:updateNodes,
-    calcInstallationFee:calcInstallationFee
+    calcInstallationFee:calcInstallationFee,
+    saveProperty: saveProperty
 };
 
 async function calcInstallationFee(data) {
@@ -233,4 +235,20 @@ function generateMarkTask(value,projectID) {
         }
     };
     return task
+}
+
+// {projectID: 5, propertyName: 'aaa', propertyValue: 1}
+function saveProperty(data, callback){
+    let obj = {};
+    let pn = 'property.' + data.propertyName;
+    obj[pn] = data.propertyValue;
+    projectsModel.update({"ID": data.projectID}, obj, function (err) {
+        if (err) {
+            logger.err(pn + ' save error: ' + err);
+            callback(err, null)
+        } else {
+            logger.info(pn + ' saved.');
+            callback('', null);
+        }}
+    );
 }

+ 1 - 0
modules/main/routes/project_route.js

@@ -13,6 +13,7 @@ module.exports = function (app) {
     projectRouter.post('/removeProjectMark', projectController.removeProjectMark);
     projectRouter.post('/updateNodes', projectController.updateNodes);
     projectRouter.post('/calcInstallationFee', projectController.calcInstallationFee);
+    projectRouter.post('/saveProperty', projectController.saveProperty);
 
     app.use('/project',projectRouter);
 };

+ 1 - 1
modules/pm/controllers/new_proj_controller.js

@@ -39,7 +39,7 @@ module.exports = {
             async function (cb) {
                 let engineeringModel = new EngineeringLibModel();
                 let engineering = await engineeringModel.getEngineering(property.engineering_id);
-                projSetting.insertData({"projectID": newProjID, main_tree_col: engineering.main_tree_col}, cb);
+                projSetting.insertData({"projectID": newProjID, main_tree_col: engineering.main_tree_col,glj_col:engineering.glj_col}, cb);
             }
         ], (err) => callback(err));
     }

+ 1 - 1
modules/pm/facade/pm_facade.js

@@ -230,7 +230,7 @@ async function copyUnitPriceFile(newProjectID,rootProjectID,userID,originaluUnit
         let rList = [];
         for(let m of mList){
             m._doc.unit_price_file_id = newFID;
-            m._doc.id = await getCounterID('mix_ratio');
+            m._doc.id = await getCounterID(model.modelName);
             rList.push(m._doc);
         }
         await insertMany(rList,model)

+ 1 - 1
modules/pm/models/templates/bills_template_model.js

@@ -40,7 +40,7 @@ class BillsTemplateModel extends BaseModel {
      */
     async getTemplateDataForNewProj (valuationId, engineering) {
         // 筛选字段
-        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1,type:1, calcBase: 1};
+        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1,type:1, calcBase: 1,feeRateID:1};
         let data = await this.findDataByCondition({valuationId: valuationId, engineering: engineering}, field, false);
 
         return data === null ? [] : data;

+ 1 - 1
modules/ration_glj/facade/ration_glj_facade.js

@@ -168,7 +168,7 @@ function createNewRecord(ration_glj) {
     newRecoed.type = ration_glj.type;
     newRecoed.repositoryId = ration_glj.repositoryId;
     newRecoed.projectGLJID = ration_glj.projectGLJID;
-    newRecoed.adjCoe = ration_glj.adjCoe
+    newRecoed.adjCoe = ration_glj.adjCoe;
     return newRecoed
 }
 

+ 5 - 1
public/web/sheet/sheet_common.js

@@ -44,7 +44,7 @@ var sheetCommonObj = {
         sheet.showRowOutline(false);
         me.buildHeader(sheet, setting);
         if (rowCount > 0)
-            sheet.setRowCount(rowCount)
+            sheet.setRowCount(rowCount);
         else
             sheet.setRowCount(1);
         sheet.resumeEvent();
@@ -139,6 +139,10 @@ var sheetCommonObj = {
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth?setting.header[col].headerWidth:100);
             }
+            if(setting.header[col].visible === false){
+                sheet.setColumnVisible(col,false);
+            }
+
         }
         for (var row = 0; row < data.length; row++) {
             //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);

+ 1 - 1
public/web/sheet/sheet_data_helper.js

@@ -57,7 +57,7 @@ var SheetDataHelper = {
         spread.options.allowUndo = false;//that.mainSpread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.z, true, false, false, false); 屏蔽undo
         spread.options.allowUserEditFormula = false;
         spread.options.showDragFillSmartTag = false;
-        spread.options.defaultDragFillType =GC.Spread.Sheets.Fill.AutoFillType.fillWithoutFormatting;
+        spread.options.defaultDragFillType = GC.Spread.Sheets.Fill.AutoFillType.fillWithoutFormatting;
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },

modules/reports/util/pdfkit_test.js → test/unit/reports/pdfkit_test.js


+ 9 - 1
web/building_saas/css/custom.css

@@ -46,4 +46,12 @@ legend.legend{
     padding: 8px;
     padding-top: 7px;
     padding-bottom: 7px;
-}
+}
+
+#gljPriceTenderCoe::-webkit-outer-spin-button,
+#gljPriceTenderCoe::-webkit-inner-spin-button {
+         -webkit-appearance: none;
+     }
+#gljPriceTenderCoe {
+    -moz-appearance: textfield;
+}

+ 8 - 1
web/building_saas/main/html/calc_program_manage.html

@@ -16,8 +16,15 @@
     <div class="container-fluid">
         <div class="row">
             <div class="col-lg-2 p-0">
-                <div class="main-data-not" id="mainSpread">
+                <div id="divSelect" style="text-align:left;height:45px;line-height:45px;">
+                    <!--<label>计算程序文件:</label>-->
+                    <select id='calcProgramFileSelect' style="width:98%;height:30px;">
+                        <option value="none">无</option>
+                        <option value="1" selected>计算程序2013标准</option>
+                        <option value="2">计算程序2018标准</option>
+                    </select>
                 </div>
+                <div class="main-data-not" id="mainSpread"></div>
             </div>
             <div class="col-lg-10 p-0">
                 <div class="main-data-not" id="detailSpread">

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

@@ -44,7 +44,7 @@
         <div class="main-nav">
             <ul class="nav nav-tabs flex-column" role="tablist">
                 <li class="nav-item"><a class="active" data-toggle="tab" href="#zaojiashu" id="tab_zaojiashu" role="tab">造价书</a></li>
-                <li class="nav-item"><a data-toggle="tab" href="#project_glj" id="tab_project_glj" data-name="tab_project_glj" role="tab">人材机</a></li>
+                <li class="nav-item"><a data-toggle="tab" href="#project_glj" id="tab_project_glj" data-name="tab_project_glj" role="tab">人材机汇总</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#fee_rates" id="tab_fee_rate" role="tab" >费率</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab">计算程序</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab">调价</a></li>
@@ -1342,6 +1342,7 @@
         <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
 
         <!-- view -->
+        <script type="text/javascript" src="/web/building_saas/main/js/views/glj_col.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/main_tree_col.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_info.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_view.js"></script>

+ 1 - 9
web/building_saas/main/html/tender_price.html

@@ -1,12 +1,4 @@
-<!--<style>
-    input::-webkit-outer-spin-button,
-    input::-webkit-inner-spin-button {
-        -webkit-appearance: none;
-    }
-    input[type="number"]{
-        -moz-appearance: textfield;
-    }
-</style>-->
+
 <div class="toolsbar px-1">
     <div class="btn-toolbar py-1">
         <div class="input-group input-group-sm mr-2">

+ 4 - 2
web/building_saas/main/js/models/calc_program.js

@@ -1548,9 +1548,11 @@ class CalcProgram {
                             rtf = parseFloatPlus(node.data.feesIndex[ft.type].totalFee).toDecimal(decimalObj.bills.totalPrice);
                             rttf = parseFloatPlus(node.data.feesIndex[ft.type].tenderTotalFee).toDecimal(decimalObj.bills.totalPrice);
                         };
+                        // 取费方式为子目含量,清单行/列的XX单价应 =ROUND( ∑ROUND(定额XX单价*含量,清单单价精度),清单单价精度)
                         if (me.project.property.billsCalcMode === leafBillGetFeeType.rationContent) {
-                            buf = (buf + (ruf * parseFloatPlus(node.data.quantity)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
-                            btuf = (btuf + (rtuf * parseFloatPlus(node.data.tenderQuantity)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
+                            buf = (buf + (ruf * parseFloatPlus(node.data.contain)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
+                            node.data.tenderContaion = (node.data.tenderQuantity / bq).toDecimal(decimalObj.decimal.process);
+                            btuf = (btuf + (rtuf * parseFloatPlus(node.data.tenderContaion)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
                         };
                         sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
                         sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);

+ 4 - 0
web/building_saas/main/js/models/project.js

@@ -318,6 +318,10 @@ var PROJECT = {
             CommonAjax.post("/project/markUpdateProject",{updateInfo:data,type:type});
         };
 
+        project.prototype.saveProperty = function (propertyName, propertyValue) {
+            CommonAjax.post("/project/saveProperty", {projectID: this.ID(), propertyName: propertyName, propertyValue: propertyValue});
+        };
+
         project.prototype.projectMarkChecking = function () {
             let  changeMark = projectInfoObj.projectInfo.changeMark;
             if(changeMark&&changeMark!=''){

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

@@ -600,8 +600,8 @@ var Ration = {
                     newNode.source = newSource;
                     newNode.sourceType = project.Ration.getSourceType();
                     newNode.data = newSource;
-                    ProjectController.syncDisplayNewNode(sheetController, newNode);
                     project.projectGLJ.loadData(function () {
+                        ProjectController.syncDisplayNewNode(sheetController, newNode);
                         project.ration_glj.addToMainTree(data.ration_gljs);
                         projectObj.mainController.refreshTreeNode([newNode], false);
                         project.calcProgram.calcAndSave(newNode,function () {

+ 36 - 0
web/building_saas/main/js/views/glj_col.js

@@ -0,0 +1,36 @@
+/**
+ * Created by zhang on 2018/7/3.
+ */
+let gljCol = {
+    ration_glj_setting: {
+        header: [
+            {headerName: "编码", headerWidth: 100, dataCode: "code", dataType: "String", formatter: "@"},
+            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 90, dataCode: "specs", dataType: "String", hAlign: "left"},
+            {headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center"},
+            {headerName: "类型", headerWidth: 45, dataCode: "shortName", dataType: "String", hAlign: "center"},
+            {headerName: "定额消耗", headerWidth: 80, dataCode: "rationItemQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},    // dataType: "Number", formatter: "0.00"
+            {headerName: "自定消耗", headerWidth: 80, dataCode: "customQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
+            {headerName: "消耗量", headerWidth: 80, dataCode: "quantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
+            {headerName: "总消耗量", headerWidth: 80, dataCode: "totalQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
+            {headerName: "定额价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", hAlign: "right", decimalField: "glj.unitPrice"},
+            {headerName: "调整价", headerWidth: 80, dataCode: "adjustPrice", dataType: "Number", hAlign: "right", decimalField: "glj.unitPrice"},
+            {headerName: "市场价", headerWidth: 80, dataCode: "marketPrice", dataType: "Number", hAlign: "right", decimalField: "glj.unitPrice"},
+            {headerName: "是否暂估", headerWidth: 65, dataCode: "isEstimate", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox"
+            }
+        ],
+        view: {
+            lockColumns: [0, 4, 5, 7, 8, 10, 12]
+        },
+        // 工料机类型是混凝土、砂浆、配合比、机械台班时,价格不可编辑。
+        editedTyep:[GLJTypeConst.MAIN_MATERIAL,GLJTypeConst.EQUIPMENT]//主材设备
+    },
+    removeCol:function (dataCode,setting) {
+       // let colIndex =
+
+
+
+    }
+
+
+};

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

@@ -88,8 +88,6 @@ var gljOprObj = {
             }
         ],
         view: {
-            comboBox: [{row: -1, col: 12, rowCount: -1, colCount: 1}],
-            lockedCells: [{row: -1, col: 3, rowCount: -1, colCount: 1}],
             lockColumns: [0, 4, 5, 7, 8, 10, 12]
         },
         // 工料机类型是混凝土、砂浆、配合比、机械台班时,价格不可编辑。

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

@@ -52,6 +52,13 @@ let MainTreeCol = {
             if((node.sourceType === projectObj.project.Ration.getSourceType()&&node.data.type!=rationType.ration)||node.sourceType==projectObj.project.ration_glj.getSourceType()){
                 return calcTools.uiGLJPrice(node.data.marketUnitFee);
             }
+        },
+        feeRate:function (node) {
+            if(node.data.feeRateID){
+                let rate = projectObj.project.FeeRate.getFeeRateByID(node.data.feeRateID);
+                if (rate) return rate.rate;
+            }
+            return node.data.feeRate;
         }
     },
     readOnly: {

+ 9 - 9
web/building_saas/main/js/views/project_glj_view.js

@@ -331,16 +331,17 @@ projectGljObject={
                 return ;
             }
         }
-
         for(let c of info.changedCells){
             let value=  info.sheet.getCell(c.row, c.col).text();
             changeInfo.push({row:c.row,col:c.col,value:value});
             if(me.projectGljEditChecking(c.row,c.col,true)==false){//如果不能编辑
                 canChange = false;
+                break;
             }
-            if (canChange==true&&!me.checkData(c.col,me.projectGljSetting,value)) {
+            if (!me.checkData(c.col,me.projectGljSetting,value)) {
                 alert('输入的数据类型不对,请重新输入!');
                 canChange = false;
+                break;
             }
         }
         if(canChange == false){//恢复原来的值
@@ -443,11 +444,7 @@ projectGljObject={
             value =  scMathUtil.roundForObj(value,getDecimal('glj.quantity'));
         }
         if(dataCode === 'is_evaluate'||dataCode === 'is_adjust_price'||dataCode === 'is_main_material'){
-            if(value){
-                value = 1;
-            }else {
-                value = 0;
-            }
+            value = value? 1:0;
         }
         if(dataCode === 'materialType'){//三材类型要做对应转换,因为这里value只是中文文本,并不是实际的值
             if(materialMap[value]!==undefined||materialMap[value]!==null){
@@ -532,7 +529,10 @@ projectGljObject={
     },
     refreshDataSheet:function () {
         let me = projectGljObject;
-        let quantityCol = 5;
+        //------------5;
+        let quantityCol = _.findIndex(me.projectGljSetting.header,function (header) {
+            return header.dataCode ==  'quantity'|| header.dataCode == 'techQuantity' || header.dataCode =='subdivisionQuantity';
+        });
         if(me.displayType == filterType.FBFX){//分部分项人材机,将“总消耗量”替换显示为“分部分项总消耗量”。
             me.projectGljSetting.header[quantityCol].dataCode = 'subdivisionQuantity';
             me.projectGljSheet.setValue(0, quantityCol, "分部分项总消耗量", GC.Spread.Sheets.SheetArea.colHeader);
@@ -543,7 +543,6 @@ projectGljObject={
             me.projectGljSetting.header[quantityCol].dataCode = 'quantity';
             me.projectGljSheet.setValue(0, quantityCol, "总消耗量", GC.Spread.Sheets.SheetArea.colHeader);
         }
-
         if(me.displayType == filterType.SCHZ){//三材汇总树节点
             me.showMaterialTreeData();
         }else {
@@ -842,6 +841,7 @@ projectGljObject={
         let prowData = parentSheet.name() == 'projectGljSheet'?me.projectGljSheetData[prow]:me.materialTree.items[prow].data;
         let updateData = {id: deleteRecode.mix_ratio_id, field: 'mix_ratio.consumption' , value: 0, market_price: parentMarketPrice, base_price: parentBasePrice};
         projectObj.project.composition.deleteComposition(updateData,deleteRecode,prowData.id,function () {
+            _.remove(me.mixRatioData,{"mix_ratio_id":deleteRecode.mix_ratio_id});
             me.refreshParentData(prow,prowData.id);
             me.mixRatioSheet.deleteRows(row,1);
             me.onUnitFileChange(deleteRecode);

+ 95 - 27
web/building_saas/main/js/views/tender_price_view.js

@@ -50,6 +50,7 @@ let tender_obj={
         this.tenderTreeSetting.setAutoFitRow = MainTreeCol.getEvent("setAutoFitRow");
         this.tenderController = TREE_SHEET_CONTROLLER.createNew(this.tenderTree, this.tenderSheet, this.tenderTreeSetting);
         this.tenderSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange);
+        this.tenderSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onTenderRangeChange);
         this.tenderSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onEditStarting);
         this.tenderController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, this.treeSelectedChanged);
        // this.tenderController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, this.onSelectionChange);
@@ -89,35 +90,85 @@ let tender_obj={
             }
         }
     },
-    onSheetValueChange : function (sender,args) {
-        let me = tender_obj, row = args.row, col = args.col;
-        let node = me.tenderTree.items[row];
-        let dataCode = me.tenderSetting.header[col].dataCode;
-        let value = args.newValue;
-        let updateData = {type:node.sourceType,data:{'ID' : node.data.ID}};
-        let datas = [],nodes = [];
+    onTenderRangeChange:function (sender,info) {
+        let me = tender_obj;
+        let changeInfo=[];
+        if(info.action == GC.Spread.Sheets.RangeChangedAction.clear){
+            if(me.editChecking(info.row,info.col) == false){
+                me.tenderController.refreshTreeNode(me.materialTree.selected, false);
+            }else {
+                info.newValue = null;
+                me.onSheetValueChange(sender,info);
+            }
+        }else {
+            let canChange = true;
+            for(let c of info.changedCells){
+                let value=  info.sheet.getCell(c.row, c.col).text();
+                changeInfo.push({row:c.row,col:c.col,value:value});
+                if(me.editChecking(c.row,c.col,true)==false){//如果不能编辑
+                    canChange = false;
+                    break;
+                }
+                if (!projectGljObject.checkData(c.col,me.tenderSetting,value)) {
+                    alert('输入的数据类型不对,请重新输入!');
+                    canChange = false;
+                    break;
+                }
+            }
+            if(canChange == false){
+                tender_obj.showTenderData();
+            }else {
+                me.batchUpdateValue(changeInfo);
+            }
+        }
 
-        if (value&&!projectGljObject.checkData(col,me.tenderSetting,value)) {
-            setTimeout(function () {//为了不与click事件冲突
-                alert('输入的数据类型不对,请重新输入!');
-            },200);
-            updateData = null;
+    },
+    batchUpdateValue:function (changeInfo) {
+        let me = tender_obj,updateNodes = [],datas = [],nodes=[];
+        let dataMap = {};//用来去重复
+        for(let c of changeInfo){
+            let dataCode = me.tenderSetting.header[c.col].dataCode;
+            let node = me.tenderTree.items[c.row];
+            me.getUpdateData(c.value,dataCode,node,updateNodes);
         }
-        if(dataCode == 'is_adjust_price'){//不调价,修改父项后,子项也跟着更新
-            if(value == true){
-                value = 1;
-            }else if(value == false){
-                value = 0;
+        for(let u of updateNodes){//有可能会有重复的数据,需要按相同的ID组合起来。
+            if(dataMap[u.data.ID]){
+                for(let key in u.data){
+                    if(key == 'ID'){
+                        continue;
+                    }
+                    dataMap[u.data.ID].data[key] = u.data[key];
+                }
+            }else {
+                dataMap[u.data.ID] = u;
             }
+        }
+        for(let IDKey in dataMap){
+            datas.push(dataMap[IDKey]);
+            let temNode = me.tenderTree.findNode(IDKey);
+            if(temNode) nodes.push(temNode);
+        }
+        me.updateTenderData(datas,function () {
+            me.tenderController.refreshTreeNode(nodes, false);
+        });
+
+    },
+
+    getUpdateData:function(value,dataCode,node,updateNodes,nodes){
+        let me = tender_obj;
+        let updateData = {type:node.sourceType,data:{'ID' : node.data.ID}};
+        if(dataCode === 'is_adjust_price'){
+            value = value? 1:0;
             if(value == 1){
                 updateData = me.cleanTenderCoe(updateData,node);//打勾不调价后清空消耗量调整系数
             }
-            me.updateChildrenValue(node,dataCode,value,datas,nodes);
+            me.updateChildrenValue(node,dataCode,value,updateNodes,nodes);
         }
         if(updateData&&dataCode.indexOf("Coe") != -1 ){//如果是调整系统项,级联更新子项
             value = scMathUtil.roundForObj(value,getDecimal('process'));
-            me.updateChildrenValue(node,dataCode,value,datas,nodes);
+            me.updateChildrenValue(node,dataCode,value,updateNodes,nodes);
         }
+
         //在目标造价综合单价中输入数值,按项目属性中的清单单价精度取舍,并清空当前行的目标造价综合合价
         if(dataCode == 'targetUnitFee'){
             value = scMathUtil.roundForObj(value,getDecimal('unitPrice',node));
@@ -127,11 +178,24 @@ let tender_obj={
             value = scMathUtil.roundForObj(value,getDecimal('totalPrice',node));
             updateData?updateData.data["targetUnitFee"] = null:'';
         }
-        if(updateData){
-            updateData.data[dataCode] = value;
-            datas.push(updateData);
+        updateData.data[dataCode] = value;
+        updateNodes.push(updateData);
+        nodes?nodes.push(node):'';
+
+    },
+
+    onSheetValueChange : function (sender,args) {
+        let me = tender_obj, row = args.row, col = args.col;
+        let node = me.tenderTree.items[row];
+        let dataCode = me.tenderSetting.header[col].dataCode;
+        let value = args.newValue;
+        let datas = [],nodes = [];
+        if (value&&!projectGljObject.checkData(col,me.tenderSetting,value)) {
+            alert('输入的数据类型不对,请重新输入!');
+            nodes.push(node);
+        }else {
+            me.getUpdateData(value,dataCode,node,datas,nodes);
         }
-        nodes.push(node);
         me.updateTenderData(datas,function () {
             me.tenderController.refreshTreeNode(nodes, false);
         });
@@ -149,7 +213,7 @@ let tender_obj={
                     continue;
                 }
                 datas.push(updateData);
-                nodes.push(c);
+                nodes?nodes.push(c):"";
             }
          }
 
@@ -287,7 +351,7 @@ let tender_obj={
         }
 
     },
-    editChecking:function (row,col) {//return false表示不能编辑
+    editChecking:function (row,col,isPaste = false) {//return false表示不能编辑
         let me = tender_obj;
         let dataCode = me.tenderSetting.header[col].dataCode;
         let lockColumns = me.tenderSetting.view.lockColumns;
@@ -295,7 +359,7 @@ let tender_obj={
         if(lockColumns.indexOf(col)!= -1){
             return false;
         }
-        if(dataCode == 'is_adjust_price'){
+        if(isPaste == false && dataCode == 'is_adjust_price'){//对于是粘贴或是拖动填充过来的数据,不调价不做判断
             return false;
         }
         if(row >=  me.tenderTree.items.length){
@@ -337,7 +401,10 @@ let tender_obj={
     doTenderCalc: function(tender){
         if (tender != tenderTypes.ttCalc)
             tender_obj.cleanCacheCoes();
-        let callback = function () { tender_obj.showTenderData() };
+        let callback = function () {
+            projectObj.project.saveProperty('hasTender', true);
+            tender_obj.showTenderData();
+        };
         projectObj.project.calcProgram.calcAllNodesAndSave(calcAllType.catAll, callback, tender);
     }
 };
@@ -372,6 +439,7 @@ $(function () {
             }
         }
         datas.push({type:ModuleNames.project,data:{'ID' : projectObj.project.ID(),'property.tenderSetting.gljPriceTenderCoe':1}});//恢复人材机单价调整系数为1。
+        datas.push({type:ModuleNames.project,data:{'ID' : projectObj.project.ID(),'property.hasTender': false}});
         me.updateTenderData(datas,function () {
             me.refreshTenderTreeByDatas(datas);
         });

+ 22 - 41
web/building_saas/report/html/rpt_print.html

@@ -13,15 +13,25 @@
         page-break-before: auto;
         page-break-after: auto;
     }
+    @page {size: A4 portrait;}
+    body {page: page}
+    div {page: page}
 </style>
-<style type="text/css">
-    svg{
-        width: 1122px;
-        height: 1122px;
+<!--
+    .printPage {
+        page: page
     }
-</style>
+    @page {size: A4 landscape;}
+    div { page: page }
+@page {margin: auto;}
+@page horizon {size: A4 landscape;}
+@page vertical1 {size: A4 portrait;}
+    @page horizon1 {size: A4 landscape;}
+    @page vertical1 {size: A4 portrait;}
+-->
 <script type="text/javascript" src="/web/building_saas/report/js/jpc_output_value_define.js"></script>
 <body onload="loading()" onbeforeunload="closing()">
+    <canvas id="chkCanvas" style="display:none"></canvas>
 </body>
 <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
 <script type="text/javascript" src="/web/building_saas/report/js/jpc_output.js"></script>
@@ -53,49 +63,20 @@
                 orgWidth = orgHeight;
                 orgHeight = tmpInt;
             }
-//            for (let i = 0; i < pageData.items.length; i++) {
-//                let div = $('<div class="pageBreak"><canvas width="' + pageWidth + '" height="' + pageHeight + '"></canvas></div>');
-//                $("body").append(div);
-//            }
-//            $(document.body).find("div").each(function(index,element){
-//                $(element).find("canvas").each(function(cIdx,elementCanvas){
-//                    canvasArr.push(elementCanvas);
-//                });
-//            });
-//            JpcCanvasOutput.scaleFactor = scaleFactor;
-//            JpcCanvasOutput.resetFonts(pageData[JV.NODE_FONT_COLLECTION]);
-//            for (let i = 0; i < canvasArr.length; i++) {
-//                JpcCanvasOutput.offsetX = -30;
-//                JpcCanvasOutput.offsetY = -30;
-//                JpcCanvasOutput.drawToCanvas(pageData, canvasArr[i], i+1);
-//            }
-
-//            let imgDataArr = [];
-//            for (let canvas of canvasArr) {
-//                imgDataArr.push(canvas.toDataURL());
-//            }
-//            let imgIdx = 0;
-//            $(document.body).find("div").each(function(index,element){
-//                let img = document.createElement('img');
-//                img.src = imgDataArr[imgIdx];
-//                img.height = orgHeight;
-//                img.width = orgWidth;
-//                imgIdx++;
-//                element.appendChild(img);
-//                $(element).find("canvas").each(function(cIdx,elementCanvas){
-//                    elementCanvas.style.display = "none";
-//                });
-//            });
 
             let svgArr = rptPrintHelper.buildSvgArr(pageData, -30, -30);
             for (let i = 0; i < pageData.items.length; i++) {
                 let div = $('<div class="pageBreak"></div>');
-//                console.log()
-//                div.append(svgArr[i]);
                 div.append($(svgArr[i].join("")));
                 $("body").append(div);
             }
-
+            $(document.body).find("div").each(function(index,element){
+                $(element).find("svg").each(function(cIdx,elementSvg){
+                    elementSvg.setAttribute('height', pageHeight);
+                    elementSvg.setAttribute('width', pageWidth);
+                });
+            });
+//            $("body").css({"page": "page"});
             window.print();
             //document.execCommand("print");
         } else {

+ 107 - 36
web/building_saas/report/js/rpt_print.js

@@ -15,20 +15,21 @@ let rptPrintHelper = {
             sessionStorage.currentPageData = null;
         }
     },
-    print: function () {
-        //
-    },
     buildSvgArr: function (pagesData, offsetX, offsetY) {
+        let me = this;
         let styles = pagesData[JV.NODE_STYLE_COLLECTION],
             fonts = pagesData[JV.NODE_FONT_COLLECTION],
             controls = pagesData[JV.NODE_CONTROL_COLLECTION]
         ;
         let rst = [];
-        for (let page of pagesData.items) {
+        let canvas = document.getElementById("chkCanvas");
+        for (let idx = 0; idx < pagesData.items.length; idx++) {
+            let page = pagesData.items[idx];
             let svgPageArr = [], pixelSize = getPixelSize(pagesData);
             svgPageArr.push("<svg width='" + pixelSize[0] + "' height='" + pixelSize[1] + "'>");
+            let adjustY = 0.5 * ((idx + 1) % 2);
             for (let cell of page.cells) {
-                svgPageArr.push(buildCellSvg(cell, fonts, styles, controls, page[JV.PROP_PAGE_MERGE_BORDER], pagesData[JV.BAND_PROP_MERGE_BAND], offsetX, offsetY));
+                svgPageArr.push(buildCellSvg(cell, fonts, styles, controls, page[JV.PROP_PAGE_MERGE_BORDER], pagesData[JV.BAND_PROP_MERGE_BAND], offsetX, offsetY, adjustY, canvas));
             }
             svgPageArr.push("</svg>");
             rst.push(svgPageArr);
@@ -37,49 +38,99 @@ let rptPrintHelper = {
     }
 };
 
-function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY) {
+function getActualBorderStyle(cell, styles, mergeBorderStyle, pageBorderArea, borderStr) {
+    let rst = styles[cell[JV.PROP_STYLE]][borderStr];
+    if (mergeBorderStyle) {
+        if (parseFloat(cell[JV.PROP_AREA][borderStr]) === parseFloat(pageBorderArea[borderStr])) {
+            if (borderStr === JV.PROP_LEFT || borderStr === JV.PROP_RIGHT) {
+                if (parseFloat(cell[JV.PROP_AREA][JV.PROP_TOP]) >= parseFloat(pageBorderArea[JV.PROP_TOP]) &&
+                    parseFloat(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) <= parseFloat(pageBorderArea[JV.PROP_BOTTOM])) {
+                    rst = mergeBorderStyle[borderStr];
+                }
+            } else if (borderStr === JV.PROP_TOP || borderStr === JV.PROP_BOTTOM) {
+                if (parseFloat(cell[JV.PROP_AREA][JV.PROP_LEFT]) >= parseFloat(pageBorderArea[JV.PROP_LEFT]) &&
+                    parseFloat(cell[JV.PROP_AREA][JV.PROP_RIGHT]) <= parseFloat(pageBorderArea[JV.PROP_RIGHT])) {
+                    rst = mergeBorderStyle[borderStr];
+                }
+            }
+        }
+    }
+    return rst;
+}
+
+function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY, adjustY, canvas) {
     let rst = [];
     let style = styles[cell[JV.PROP_STYLE]];
     let mergeBandStyle = null;
     if (rptMergeBorder) {
-        mergeBandStyle = styles[rptMergeBorder[JV.PROP_STYLE]];
+        mergeBandStyle = styles[rptMergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+    }
+    let font = cell[JV.PROP_FONT];
+    if (typeof font === 'string') {
+        font = fonts[cell[JV.PROP_FONT]];
     }
     let left = parseInt(cell[JV.PROP_AREA][JV.PROP_LEFT]) + offsetX + 0.5,
         right = parseInt(cell[JV.PROP_AREA][JV.PROP_RIGHT]) + offsetX + 0.5,
-        top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + 0.5,
-        bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + 0.5,
-        x = left, y = top,
-        text_anchor = "start"
+        top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + adjustY,
+        bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + adjustY
     ;
     if (style) {
-        if (style[JV.PROP_LEFT] && parseFloat(style[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) > 0) {
+        let leftBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_LEFT);
+        // if (style[JV.PROP_LEFT] && parseFloat(style[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) > 0) {
+        if (leftBS && parseFloat(leftBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + top +
                 "' x2='" + left + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:1'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + leftBS[JV.PROP_LINE_WEIGHT] +"'/>")
         }
-        if (style[JV.PROP_RIGHT] && parseFloat(style[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) > 0) {
+        let rightBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_RIGHT);
+        // if (style[JV.PROP_RIGHT] && parseFloat(style[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) > 0) {
+        if (rightBS && parseFloat(rightBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + right + "' y1='" + top +
                 "' x2='" + right + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:1'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + rightBS[JV.PROP_LINE_WEIGHT] +"'/>")
         }
-        if (style[JV.PROP_TOP] && parseFloat(style[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) > 0) {
+        let topBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_TOP);
+        // if (style[JV.PROP_TOP] && parseFloat(style[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) > 0) {
+        if (topBS && parseFloat(topBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + top +
                 "' x2='" + right + "' y2='" + top +
-                "' style='stroke:rgb(0,0,0);stroke-width:1'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + topBS[JV.PROP_LINE_WEIGHT] +"'/>")
         }
-        if (style[JV.PROP_BOTTOM] && parseFloat(style[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) > 0) {
+        let bottomBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_BOTTOM);
+        // if (style[JV.PROP_BOTTOM] && parseFloat(style[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) > 0) {
+        if (bottomBS && parseFloat(bottomBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + bottom +
                 "' x2='" + right + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:1'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + bottomBS[JV.PROP_LINE_WEIGHT] +"'/>")
         }
     }
-    let font = cell[JV.PROP_FONT];
-    if (typeof font === 'string') {
-        font = fonts[cell[JV.PROP_FONT]];
-    }
-    let fontsize = Math.round(parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]) * 3 / 4);
+    buildText(rst, cell, font, controls[cell[JV.PROP_CONTROL]], offsetX, offsetY, adjustY, canvas);
+
+    return rst.join("");
+}
+
+function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas) {
+    let orgFontHeight = parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]);
     let fontWeight = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold":"normal";
-    let control = controls[cell[JV.PROP_CONTROL]];
+    let fontStyle = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"normal";
+    let left = parseInt(cell[JV.PROP_AREA][JV.PROP_LEFT]) + offsetX + 0.5,
+        right = parseInt(cell[JV.PROP_AREA][JV.PROP_RIGHT]) + offsetX + 0.5,
+        top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + adjustY,
+        bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + adjustY,
+        x = left, y = top,
+        text_anchor = "start"
+    ;
+    let value = cell[JV.PROP_VALUE];
+    if (!(value)) {
+        value = "";
+    }
+    let values = null;
+    if (typeof value === "string") {
+        values = value.split("|");
+    } else {
+        values = [value];
+    }
+    let stepHeight = (parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) - parseInt(cell[JV.PROP_AREA][JV.PROP_TOP])) / values.length;
     if (control) {
         if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "left") {
             text_anchor = "start";
@@ -91,19 +142,39 @@ function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBo
             text_anchor = "middle";
             x = Math.round((left + right) / 2);
         }
-        if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "top") {
-            y = top + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "bottom") {
-            y = bottom - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "center") {
-            y = Math.round((top + bottom + fontsize) / 2 );
+    }
+    for (let vidx = 0; vidx < values.length; vidx++) {
+        //check whether need to adjust the font size
+        let ctx = canvas.getContext("2d");
+        let dftFontHeight = orgFontHeight;
+        ctx.font = ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold ":"") + ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"") + dftFontHeight + "px " + font[JV.PROP_NAME];
+        while ((right - left) <= ctx.measureText(values[vidx]).width) {
+            if (dftFontHeight > 6) {
+                dftFontHeight--;
+                ctx.font = ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold ":"") + ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"") + dftFontHeight + "px " + font[JV.PROP_NAME];
+            } else {
+                break;
+            }
+        }
+        dftFontHeight = (dftFontHeight * 3 / 4); //SVG的字体与canvas的字体大小的切换, 不用考虑取整
+        if (control) {
+            if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "top") {
+                y = Math.round((top + vidx * stepHeight) + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP]);
+            } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "bottom") {
+                y = Math.round((top + (vidx + 1) * stepHeight) - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]);
+            } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "center") {
+                y = Math.round(((top + vidx * stepHeight) + (top + (vidx + 1) * stepHeight) + dftFontHeight) / 2 );
+            }
+        }
+        if (font[JV.PROP_NAME] === "宋体") {
+            y--;
         }
+        destRst.push("<text style='fill:black;font-family:" + font[JV.PROP_NAME] +
+            ";font-weight:" + fontWeight +
+            ";font-style:" + fontStyle +
+            ";font-size:" + dftFontHeight + "pt' x='" +
+            x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'>" + values[vidx] + "</text>");
     }
-    rst.push("<text style='fill:black;font-family:" + font[JV.PROP_NAME] +
-        ";font-weight:" + fontWeight +
-        ";font-size:" + fontsize + "pt' x='" +
-        x +"' y='" + y + "' text-anchor='" + text_anchor + "'>" + cell[JV.PROP_VALUE] + "</text>");
-    return rst.join("");
 }
 
 function getPixelSize(pagesData) {