Selaa lähdekoodia

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost into 1.0.0_online

zhongzewei 6 vuotta sitten
vanhempi
commit
bd23908322

+ 12 - 1
config/config.js

@@ -28,7 +28,18 @@ module.exports = {
                 useMongoClient: true
             }
     },
-    pp:{  server: "112.74.42.187",
+    pp:{  server: "172.18.111.231",
+        port: "27017",
+        options:{
+            user:'smartcost',
+            pass:'SmartCost3850888',
+            auth: {
+                "authdb": "admin"
+            },
+            connectTimeoutMS: 50000,
+            useMongoClient: true
+        }},
+    ab:{  server: "112.74.42.187",
         port: "27017",
         options:{
             user:'smartcost',

+ 1 - 0
modules/all_models/ration_template.js

@@ -14,6 +14,7 @@ let ration_template =  new Schema({
         code:String,
         name:String,
         type:String,
+        defaultLocation:String,//记录默认给定的清单编号,恢复原始数据时用(目前复制整块)
         billsLocation:String,//这个是清单编号
         fxID:String,//这个是分项对应的ID
         unit:String,

+ 39 - 5
modules/fee_rates/facade/fee_rates_facade.js

@@ -33,7 +33,8 @@ module.exports={
     updateFeeRates:updateFeeRates,
     updateRates:update_rates,
     feeRateFileSaveAs:feeRateFileSaveAs,
-    getFeeRateByID:getFeeRateByID
+    getFeeRateByID:getFeeRateByID,
+    changeFeeRateFile:changeFeeRateFile
 };
 let operationMap={
     'ut_create':create_fee_rate,
@@ -401,7 +402,7 @@ async function updateFeeRates(datas){//批量更新费率
 async function changeFeeRateFileFromCurrent(jdata){
     let data = JSON.parse(jdata);
     let newFeeRateFile=data.newFeeRateFile;
-    let result = await  projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':newFeeRateFile});
+    await changeFeeRateFile(data,newFeeRateFile,0);
     let feeRateData = await feeRateFileModel.findOne({'ID':newFeeRateFile.id});
     if(feeRateData!==null){
         let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
@@ -412,10 +413,43 @@ async function changeFeeRateFileFromCurrent(jdata){
     return feeRateData;
 }
 
+async function changeFeeRateFile(projectData,feeRateFile,type,userID) {
+    let temFile=null,newFeeRateFile = {};
+    if(type == 0){//从本建设项目中替换,直接赋值
+        temFile =  feeRateFile
+    }else if(type == 1) {//从其它建设项目中复制
+        let oldFeeRateFile = await feeRateFileModel.findOne({'ID':feeRateFile.id});
+        let feeRate = await feeRateModel.findOne({ID:oldFeeRateFile.feeRateID});
+        let newFeeRate={};
+        if(! feeRate){
+            throw '不存在对应费率文件';
+        }
+        newFeeRate.ID=uuidV1();
+        newFeeRate.rates =feeRate.rates;
+        newFeeRateFile.ID = uuidV1();
+        newFeeRateFile.name = feeRateFile.name;
+        newFeeRateFile.userID = userID;
+        newFeeRateFile.libName = oldFeeRateFile.libName;
+        newFeeRateFile.libID=oldFeeRateFile.libID;
+        newFeeRateFile.rootProjectID = projectData.rootProjectID;
+        newFeeRateFile.feeRateID =newFeeRate.ID;
+        await feeRateModel.create(newFeeRate);
+        await feeRateFileModel.create(newFeeRateFile);
+        temFile={
+            id:newFeeRateFile.ID,
+            name:feeRateFile.name
+        };
+        newFeeRateFile.rates=newFeeRate.rates;//构建返回数据
+    }
+    await  projectsModel.findOneAndUpdate({ID:projectData.projectID},{'property.feeFile':temFile});
+    return newFeeRateFile
+}
+
+
 async function changeFeeRateFileFromOthers(jdata) {
     let data = JSON.parse(jdata);
-    console.log(data);
-    let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
+    let newFeeRateFile = await changeFeeRateFile(data,{id:data.feeRateFileID,name:data.name},1,data.userID);
+   /* let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
     let feeRate = await feeRateModel.findOne({ID:feeRateFile.feeRateID});
     let newFeeRate={};
     newFeeRate.ID=uuidV1();
@@ -435,7 +469,7 @@ async function changeFeeRateFileFromOthers(jdata) {
         name:data.name
     }
     await projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':feeFile});
-    newFeeRateFile.rates=newFeeRate.rates;
+    newFeeRateFile.rates=newFeeRate.rates;*/
     newFeeRateFile.usageProjects=await getUsageProjects(newFeeRateFile.ID);
     return newFeeRateFile;
 }

+ 80 - 0
modules/glj/facade/glj_facade.js

@@ -0,0 +1,80 @@
+/**
+ * Created by zhang on 2019/1/2.
+ */
+module.exports={ //先导出后require可以解决循环引用问题
+    changeUnitFile:changeUnitFile
+};
+
+const ProjectModel = require('../../pm/models/project_model').project;
+import UnitPriceFileModel from "../models/unit_price_file_model";
+import UnitPriceModel from "../models/unit_price_model";
+
+async function changeUnitFile(projectData,unitFile,type,userID) {
+    let projectId = projectData.projectID;
+    let changeUnitPriceId = unitFile.id;
+    let newName = unitFile.name;
+    type = parseInt(type);
+
+        let currentUnitPriceId = await ProjectModel.getUnitPriceFileId(projectId);
+        let unitPriceFileModel = new UnitPriceFileModel();
+
+        let insertData = null;
+        if (type > 0) {
+            let currentUnitPrice = await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId});
+            if (currentUnitPrice === null) {
+                throw '不存在对应单价文件';
+            }
+            // 获取当前项目的rootProjectId
+            let projectData = await ProjectModel.getProject(projectId);
+            let rootProjectId = projectData.property.rootProjectID !== undefined ? projectData.property.rootProjectID : 0;
+
+            insertData = JSON.parse(JSON.stringify(currentUnitPrice));
+            insertData.root_project_id = rootProjectId;
+            newName?insertData.name = newName:'';
+            insertData.user_id = userID;
+            delete insertData._id;
+            delete insertData.ID;
+        }
+        // 获取即将更改的单价文件信息
+        let targetUnitPriceFile = type === 0 ? await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId}) :
+            await unitPriceFileModel.add(insertData);
+        if (targetUnitPriceFile === null) {
+            throw '没有找到对应的单价文件';
+        }
+
+        // 查找对应单价文件的项目工料机数据
+        let unitPriceModel = new UnitPriceModel();
+        if(type ===1){//从其它项目复制,则先复制一份数据。
+            let needCopyList = await unitPriceModel.findDataByCondition({unit_price_file_id: changeUnitPriceId}, null, false);
+            if(needCopyList){
+                // 过滤mongoose格式
+                needCopyList = JSON.stringify(needCopyList);
+                needCopyList = JSON.parse(needCopyList);
+                let copyList = [];
+                for(let n of needCopyList){
+                    delete n._id;  // 删除原有id信息
+                    delete n.id;
+                    n.unit_price_file_id = targetUnitPriceFile.id;
+                    copyList.push(n);
+                }
+                copyList.length>0 ? await unitPriceModel.add(copyList):'';
+            }
+        }
+
+
+        let copyResult = await unitPriceModel.copyNotExist(currentUnitPriceId, targetUnitPriceFile.id,projectId);
+        // 复制成功后更改project数据
+        if (!copyResult) {
+            throw '复制数据失败';
+        }
+
+        let changeUnitPriceFileInfo = {
+            id: targetUnitPriceFile.id,
+            name: targetUnitPriceFile.name
+        };
+        let result = ProjectModel.changeUnitPriceFileInfo(projectId, changeUnitPriceFileInfo);
+        if (!result) {
+            throw '切换单价文件失败!';
+        }
+        return changeUnitPriceFileInfo;
+}

+ 16 - 3
modules/glj/models/unit_price_file_model.js

@@ -8,9 +8,8 @@
 import mongoose from "mongoose";
 import BaseModel from "../../common/base/base_model";
 import CounterModel from "./counter_model";
-const ProjectModel = require('../../pm/models/project_model').project;
 let collectionName = 'unit_price_file';
-
+let Projects = mongoose.model('projects');
 class UnitPriceFileModel extends BaseModel {
 
     /**
@@ -74,7 +73,7 @@ class UnitPriceFileModel extends BaseModel {
                 throw '标段id有误';
             }
 
-            let unitPriceFileId =await ProjectModel.getUnitPriceFileId(projectId);
+            let unitPriceFileId =await this.getUnitPriceFileId(projectId);
             if (unitPriceFileId <= 0) {
                 throw '没有对应的单价文件';
             }
@@ -88,6 +87,20 @@ class UnitPriceFileModel extends BaseModel {
         return result;
     }
 
+    async getUnitPriceFileId(projectId){
+        let result = 0;
+        let startTime = +new Date();
+        let projectData = await Projects.find({ID: projectId},['property.unitPriceFile']);
+        if (projectData === null) {
+            return result;
+        }
+        let endTime = +new Date();
+        console.log("取单价文件列表id时间-----"+(endTime - startTime));
+        projectData = projectData[0];
+        result = projectData.property.unitPriceFile !== undefined ? projectData.property.unitPriceFile.id : 0;
+        return result;
+    }
+
     /**
      * 新增单条工料机数据
      *

+ 34 - 2
modules/main/facade/block_lib_facade.js

@@ -42,7 +42,39 @@ async function getLibNamesAndFirstLib(data) {
 
 
 async function copyTemplateLib(userID, userName, compilationID) {
-    let template = await getLib({libID: '00000000'});
+    // let template = await getLib({libID: '00000000'});
+    let template = {
+        libID: "00000000",
+        libName: "模板",
+        datas: [
+            {
+                "ID": "00000001",
+                "ParentID": "-1",
+                "NextSiblingID": "00000002",
+                "type": 1,
+                "nodeName": "分类1"
+            },
+            {
+                "ID": "00000002",
+                "ParentID": "-1",
+                "NextSiblingID": "00000003",
+                "type": 1,
+                "nodeName": "分类2"
+            },
+            {
+                "ID": "00000003",
+                "ParentID": "-1",
+                "NextSiblingID": "-1",
+                "type": 1,
+                "nodeName": "分类3"
+            }
+        ],
+        share: {
+            "shareName": "共享",
+            "shareTo": []
+        }
+    };
+
     let newLib = {
         userID: userID,
         compilationID: compilationID,
@@ -53,7 +85,7 @@ async function copyTemplateLib(userID, userName, compilationID) {
     };
     newLib.share.shareName = `共享-${newLib.libName}`;
     await blModel.create(newLib);
-    console.log(JSON.stringify(newLib));
+    // console.log(JSON.stringify(newLib));
     return newLib;
 };
 

+ 10 - 10
modules/main/facade/project_facade.js

@@ -24,7 +24,8 @@ module.exports = {
     updateNodes:updateNodes,
     calcInstallationFee:calcInstallationFee,
     saveProperty: saveProperty,
-    getDefaultColSetting: getDefaultColSetting
+    getDefaultColSetting: getDefaultColSetting,
+    markProjectsToChange:markProjectsToChange
 };
 
 async function calcInstallationFee(data) {
@@ -214,9 +215,7 @@ async function updateNodes(datas){
 
 //data = {feeRateID:111111,projectID:1245}; type = feeRate
 async function markUpdateProject(data,type) {
-    let tasks=[];
     let query = {deleteInfo:null};
-    let result = null;
     if(type=="feeRate"){//更改了费率
         query['property.feeFile.id'] = data.feeRateID;
     }
@@ -224,15 +223,16 @@ async function markUpdateProject(data,type) {
         query['property.unitPriceFile.id'] = data.unitFileID;//unitPriceFile
     }
     let projects = await projectsModel.find(query);
+    return await markProjectsToChange(projects,type,data.projectID);
+}
+
+async function markProjectsToChange(projects,type,extProjectID){
+    let tasks=[];
     for(let p of projects){
-        if(p.ID!=data.projectID){//当前项目不用更新
-            tasks.push(generateMarkTask(type,p.ID));
-        }
-    }
-    if(tasks.length>0){
-        result = await projectsModel.bulkWrite(tasks);
+        if(extProjectID && p.ID===extProjectID) continue;//排除当前项目
+        tasks.push(generateMarkTask(type,p.ID));
     }
-    return result;
+    return tasks.length>0 ? await projectsModel.bulkWrite(tasks):null;
 }
 
 async function removeProjectMark(projectID) {

+ 2 - 1
modules/main/facade/ration_facade.js

@@ -215,7 +215,7 @@ async function addRationSubList(stdRation,newRation,needInstall,compilation) {
     console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
     //添加定额模板子目
     let ration_template = await addRationTemplate(stdRation,newRation);
-    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:[ration_template]};
+    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[]};
 }
 
 async function addRationInstallFee(std,newRation) {
@@ -274,6 +274,7 @@ async function addRationTemplate(std,newRation) {
                 template.type = tem.type;
                 template.unit = re_ration.unit;
                 template.billsLocation = tem.billsLocation;
+                template.defaultLocation = tem.billsLocation;
                 templateList.push(template)
             }
         }

+ 12 - 0
modules/pm/controllers/pm_controller.js

@@ -646,4 +646,16 @@ module.exports = {
             callback(req, res, 1, err, null);
         }
     },
+    changeFile:async function(req,res){
+        try{
+            let data = JSON.parse(req.body.data);
+            console.log(data);
+            await pm_facade.changeFile(data.projects,data.user_id,data.fileID,data.name,data.from,data.type);
+            callback(req, res, 0, 'success', []);
+        }
+        catch (err){
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    }
 };

+ 49 - 23
modules/pm/facade/pm_facade.js

@@ -1,9 +1,38 @@
 /**
  * Created by zhang on 2018/4/17.
  */
+const projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+//先导出后require可以解决循环引用问题
+module.exports={
+    moveProject:moveProject,
+    copyProject:copyProject,
+    copyExample: copyExample,
+    getSummaryInfo: getSummaryInfo,
+    getSummaryInfoByTender: getSummaryInfoByTender,
+    getTendersFeeInfo: getTendersFeeInfo,
+    getConstructionProject: getConstructionProject,
+    getFullPath: getFullPath,
+    getProjectFeature:getProjectFeature,
+    projectType: projectType,
+    getPosterityProjects: getPosterityProjects,
+    isShare: isShare,
+    getShareInfo: getShareInfo,
+    prepareInitialData: prepareInitialData,
+    changeFile:changeFile
+};
+
+
+
 let mongoose = require('mongoose');
 let _ = require("lodash");
 let feeRate_facade = require('../../fee_rates/facade/fee_rates_facade');
+let glj_facade = require('../../glj/facade/glj_facade');
+let project_facade = require('../../main/facade/project_facade');
 let logger = require("../../../logs/log_helper").logger;
 const uuidV1 = require('uuid/v1');
 let projectModel = mongoose.model('projects');
@@ -23,6 +52,7 @@ let rationGLJModel = mongoose.model('ration_glj');
 let rationCoeModel = mongoose.model('ration_coe');
 let rationInstallationModel = mongoose.model('ration_installation');
 let quantityDetailModel = mongoose.model('quantity_detail');
+let rationTemplateModel = mongoose.model('ration_template');
 let userModel = mongoose.model('user');
 let compleGljSectionModel = mongoose.model('complementary_glj_section');
 let compleGljSectionTModel = mongoose.model('complementary_glj_section_templates');
@@ -35,31 +65,9 @@ let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment';
 import billsFlags from '../../common/const/bills_fixed';
-const projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
 
 
-module.exports={
-    moveProject:moveProject,
-    copyProject:copyProject,
-    copyExample: copyExample,
-    getSummaryInfo: getSummaryInfo,
-    getSummaryInfoByTender: getSummaryInfoByTender,
-    getTendersFeeInfo: getTendersFeeInfo,
-    getConstructionProject: getConstructionProject,
-    getFullPath: getFullPath,
-    getProjectFeature:getProjectFeature,
-    projectType: projectType,
-    getPosterityProjects: getPosterityProjects,
-    isShare: isShare,
-    getShareInfo: getShareInfo,
-    prepareInitialData: prepareInitialData,
-};
 
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
@@ -205,7 +213,8 @@ async function copyProject(userID, compilationID,data,newProjectID = null) {
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationGLJModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationCoeModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,quantityDetailModel),
-        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel)
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel),
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationTemplateModel)
     ];
     if(originalProperty.calcProgramFile){
         copyTasks.push(commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel));
@@ -293,6 +302,7 @@ async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
         if(doc.billsItemID){
             doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
         }
+        if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
         //绑定定类型的工料机 项目工料机ID
         doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
     }
@@ -961,3 +971,19 @@ async function copyCompleGljSection(userId, compilationId) {
         await compleGljSectionModel.insertMany(insertDatas);
     }
 }
+
+async function changeFile(datas,userID,fileID,name,from,type){//from 费率或单价文件,type从单前建设项目还是从其它建设项目中复制
+    let projectIDs = [],newFile = {id:fileID,name:name};//计录从其它项目中复制的文件,选中多个的时候只需复制一次
+    let projectUpdateType = from == "feeRateFile"?"feeRate":"unitFile";
+    for(let d of datas){
+        let tem_file = from == "feeRateFile"? await feeRate_facade.changeFeeRateFile(d, newFile,type,userID):await glj_facade.changeUnitFile(d, newFile,type,userID);
+        if(type == 1 && tem_file){//从建设项目复制时,只有第一次需要复制,剩下的就相当于使用同个建设项目的情况了
+            let newID =  from == "feeRateFile"?tem_file.ID:tem_file.id;
+            newFile = {id:newID,name:tem_file.name};
+            type = 0;
+        }
+        projectIDs.push({ID:d.projectID})
+    }
+    await project_facade.markProjectsToChange(projectIDs,projectUpdateType)//项目标记为待刷新状态
+
+}

+ 18 - 19
modules/pm/models/project_model.js

@@ -1,6 +1,22 @@
 /**
  * Created by Mai on 2017/1/18.
  */
+let projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
+//先导出后require可以解决循环引用问题
+module.exports ={    project: new ProjectsDAO(),
+    projType: projectType,
+    fileType: fileType
+};
+
 import mongoose from 'mongoose';
 import async_c from 'async';
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
@@ -34,19 +50,9 @@ let Projects = mongoose.model('projects');
 let mainColLibModel = mongoose.model('std_main_col_lib');
 let projSettingModel = mongoose.model('proj_setting');
 let optionModel = mongoose.model('options');
-let projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
-let fileType = {
-    unitPriceFile: 'UnitPriceFile',
-    feeRateFile: 'FeeRateFile'
-};
 
-let ProjectsDAO = function () {
-};
+function ProjectsDAO() {
+}
 
 let G_FILE_VER = '1.0.1';
 
@@ -844,11 +850,4 @@ ProjectsDAO.prototype.defaultSettings = async function (userID, compilationId, p
     await optionModel.update({user_id: userID, compilation_id: compilationId}, {$set: {options: optionSetting}});
     await Projects.update({ID: projectID}, {$set: {property: cloneProperty}});
     return true;
-};
-
-
-
-module.exports ={    project: new ProjectsDAO(),
-    projType: projectType,
-    fileType: fileType
 };

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

@@ -60,6 +60,7 @@ module.exports = function (app) {
     pmRouter.post('/getProjectShareInfo', pmController.projectShareInfo);
     pmRouter.post('/share', pmController.share);
     pmRouter.post('/receiveProjects', pmController.receiveProjects);
+    pmRouter.post('/changeFile', pmController.changeFile);
 
     app.use('/pm/api', pmRouter);
 };

+ 0 - 1
public/web/socket/connection.js

@@ -41,7 +41,6 @@ socketObject={
           //window.location.reload();
       });
       socket.on('unitFileChange', function (data) {
-          data = JSON.parse(data);
           /*console.log(data);
           if (data.newValue === undefined) {
               return false;

+ 14 - 0
socket.js

@@ -15,6 +15,7 @@ socketIO.on('connection', function(socket) {
     console.log("new connection");
     // 加入房间
     socket.on('join', function(data) {
+        console.log(data);
         for(let key in data){
             roomInfo[key] = data[key];
             socket.join(data[key]);
@@ -44,6 +45,19 @@ socketIO.on('connection', function(socket) {
             socket.broadcast.to(data.userID).emit('refreshProjectIcon', data);
         }
     });
+    socket.on('multiFileChangeNotify', function(data) {
+        console.log(data);
+        let projectID = data.projects[0].projectID;
+        let userID = data.user_id;
+        if(projectID && userID){//通知项目管理页面
+            socket.broadcast.to(userID).emit('fileDataChange', {projectID:projectID});
+        }
+        for(let fileID of data.oldFileIDs){//通知已打开的项目页面
+            let messageTitle = data.from == "feeRateFile"?"feeRateChange":"unitFileChange";
+            socket.broadcast.to(fileID).emit(messageTitle, data);
+        }
+    });
+
 
     socket.on('disconnect', function () {
         console.log("client disconnect =========="+JSON.stringify(roomInfo));

+ 5 - 0
web/building_saas/css/custom.css

@@ -305,4 +305,9 @@ input.text-right{
 /*修改tooltip默认最大宽度 */
 .tooltip-inner{
     max-width: 400px !important;
+}
+.applySuccess{
+    display: none;
+    color: #43CD80;
+    margin-left: 8px
 }

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

@@ -304,6 +304,7 @@
                                                       </div>
                                                       <div class="">
                                                           <button class=" btn btn-primary btn-sm cus-width" type="button" id="apply_mbzm">应用</button>
+                                                          <label class="applySuccess" ><i class="fa fa-check" aria-hidden="true"></i>成功</label>
                                                           <button class=" btn btn-primary btn-sm cus-width" type="button" id="next_mbzm">下一条</button>
                                                       </div>
 

+ 9 - 1
web/building_saas/main/js/controllers/block_controller.js

@@ -340,7 +340,7 @@ let BlockController = {
                 i==0?firstNode = temNode:'';
             }
         }
-        ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes);
+        ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes,true);
         let sels = projectObj.mainController.sheet.getSelections();
         //设置选中并更新下方显示
         projectObj.mainController.setTreeSelected(firstNode);
@@ -475,6 +475,14 @@ let BlockController = {
             template.ID = uuid.v1();
             template.projectID = projectObj.project.ID();
             template.rationID = rationData.ID;
+            //其它值恢复成默认
+            for(let t of template.templateList){
+                t.billID = "";
+                t.fxID="";
+                t.quantity="0";
+                t.coe = "";
+                if(t.defaultLocation) t.billsLocation = t.defaultLocation;
+            }
             return template;
         }
         

+ 2 - 2
web/building_saas/main/js/controllers/project_controller.js

@@ -16,7 +16,7 @@ ProjectController = {
             cbTools.refreshFormulaNodes();
         });
     },
-    syncDisplayNewNodes: function (sc, newNodes) {
+    syncDisplayNewNodes: function (sc, newNodes,withOutSelect=false) {//withOutSelect 不需要自动选中,外面自已处理
         TREE_SHEET_HELPER.massOperationSheet(sc.sheet, function () {
             var sels = sc.sheet.getSelections();
             newNodes.sort(function (a, b) {
@@ -36,7 +36,7 @@ ProjectController = {
                 lastNode = newNode
                // sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
             }
-            if(lastNode){
+            if(withOutSelect==false&& lastNode){
                 sc.setTreeSelected(lastNode);
                 sc.sheet.setSelection(lastNode.serialNo(), sels[0].col, 1, 1);
             }

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

@@ -22,6 +22,8 @@ $(function () {
         billsLibObj.refreshBillsSpread();
         billsLibObj.refreshBillsRelaSpread();
         rationLibObj.refreshSpread();
+        subObj.initGljSubTab();
+        refreshSubSpread();
     });
 
     $('#tab_report').on('shown.bs.tab', function(e){

+ 7 - 3
web/building_saas/main/js/views/mbzm_view.js

@@ -181,11 +181,15 @@ let mbzm_obj={
                 projectObj.project.calcProgram.calcNodesAndSave(calRations,function () {
                     installationFeeObj.calcInstallationFee();
                 });
-
+                mbzm_obj.showApplySuccess();
             });
-            console.log(result);
         })
-
+    },
+    showApplySuccess:function () {
+        $(".applySuccess").show();
+        setTimeout(function () {
+            $(".applySuccess").hide();
+        },1500)
     },
     positionChecking(type,data){//这个要之后再测试一下
         let validate = true;

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

@@ -1234,6 +1234,7 @@ $(function () {
             changeUnitPriceId = $("#self-file").val();
             if(!changeUnitPriceId){
                 alert('单价文件不可为空');
+                return;
             }
             submitFileChange(changeUnitPriceId,type);
         } else {

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

@@ -97,7 +97,7 @@ let subObj = {
         let totalWidth = $('#subItems').width();
         //人材机和项目特征文本比例
         const openWidth = 30;//打开项目特征工具条
-        const tab_tem = (305+openWidth+10+30)/totalWidth;//tab显示框默认宽度:305(表格宽度) + 30(工具条宽度)+10(resize div 宽度)+30(序号列宽度)
+        const tab_tem = (305+openWidth+10)/totalWidth;//tab显示框默认宽度:305(表格宽度) + 30(工具条宽度)+10(resize div 宽度)
         let textVisible = $('#replaceText').is(':visible'),
             //默认比例
             textPercent = tab_tem * 100 + '%',//'15%',

+ 1 - 1
web/building_saas/main/js/views/zmhs_view.js

@@ -19,7 +19,7 @@ let zmhs_obj = {
         },
         getText:{
             forContent:function (item) {//所选人材机,内容和条件互换位置
-               if(gljUtil.isDef(item.select_code)&&item.select_code!=""){
+               if(gljUtil.isDef(item.option_codes)&&item.option_codes!=""){
                    return item.name;
                }else {
                    return item.content;

+ 2 - 2
web/building_saas/pm/html/project-management.html

@@ -671,7 +671,7 @@
                                 <select class="form-control" id="otherFileOptions">
                                     <option>10.9建筑例题内测单价文件</option><!--建设项目下单价文件-->
                                 </select>
-                                <span class="form-text text-muted">你选择的单价文件将复制一份至新项目,不会影响原建设项目的单价文件。</span>
+                                <span class="form-text text-muted">你选择的文件将复制一份至新项目,不会影响原建设项目的文件。</span>
                             </div>
                         </div>
 
@@ -680,7 +680,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <button type="button" class="btn btn-primary mr-3" data-dismiss="modal" id="changeFileConfirm">确定</button>
+                <button type="button" class="btn btn-primary mr-3" id="changeFileConfirm">确定</button>
             </div>
         </div>
     </div>

+ 50 - 5
web/building_saas/pm/js/pm_newMain.js

@@ -1226,18 +1226,63 @@ const projTreeObj = {
             }
         }
     },
-    confirmFileChange : function(){
-        let selectProjects =[];
-        for(let i of this.replaceTree.items){
-            if(i.data.selected === 1) selectProjects.push(i)
+    confirmFileChange :async function(){
+        let selectProjects =[],fileID=null,from = $("#mr_from").val(),name='',oldFileIDs = [],validate = true;
+        for(let i of this.replaceTree.items) {
+            if (i.data.selected === 1){
+                selectProjects.push({
+                    projectID: i.data.ID,
+                    rootProjectID: i.data['property']['rootProjectID']
+                });
+                let fileField = from == "feeRateFile" ? "feeFile" : "unitPriceFile";
+                oldFileIDs.push(i.data['property'][fileField]['id']);
+            }
         }
-        console.log(selectProjects);
         if(selectProjects.length > 0){
+            let type = parseInt($("input[name='select_from']:checked").val());//0 从当前建设项目,1从其它建设项目中复制
+            if(type == 0){
+                fileID = $("#currentOptions").val();
+                name = $("#currentOptions").find("option:selected").text()
+            }else {
+                fileID = $("#otherFileOptions").val();
+                name = $("#otherFileOptions").find("option:selected").text();
+            }
+            if(fileID == null || fileID == undefined|| fileID ==""){
+                alert("请选择替换文件")
+            }
+            //从其它项目复制才要做重名检查
+            if(type == 1) validate = await projTreeObj.fileNameChecking({ name:name,rootProjectID:selectProjects[0].rootProjectID},from);
+            if (validate == true){
+                $('#m_replace_file').modal('hide');
+                await projTreeObj.postChangeFile({projects:selectProjects,fileID:fileID,name:name,type:type,from:from},oldFileIDs);
+            }else {
+                alert(`当前的建设项目中已经有相同名字的${from == "feeRateFile"?"费率":"单价"}文件!`);
+            }
 
         }
+    },
+    fileNameChecking:async function(data,from){
+        let url =from == "feeRateFile" ? "/feeRates/checkFeeRateName" : "/glj/checkUnitFileName";
+        let reuslt = await ajaxPost(url,data);
+        return reuslt == false;//result 为true 则有重名的文件
+    },
 
+    postChangeFile:async function(data,oldFileIDs){
+        data.user_id = userID;
+        $.bootstrapLoading.start();
+        let result = await ajaxPost("/pm/api/changeFile",data);
+        $.bootstrapLoading.end();
+        projTreeObj.refreshWhenFileDateChange(data.projects[0].projectID);
+        //发送文件改变消息
+        data.oldFileIDs = _.uniq(oldFileIDs);
+        socket.emit('multiFileChangeNotify', data);
 
+        console.log(result);
     },
+    checkFileName:async function (fileID,name,type) {
+        let node = this.tree.selected;
+    },
+
     insert: function (data, parent, next) {
         let preNode = this.tree.items[this.preSelection.row];
         let node = this.tree.addNodeData(data, parent, next);

+ 3 - 2
web/building_saas/report/html/rpt_print.html

@@ -37,6 +37,7 @@
 <script type="text/javascript" src="/web/building_saas/report/js/jpc_output.js"></script>
 <script type="text/javascript" src="/web/building_saas/report/js/rpt_print.js"></script>
 <SCRIPT type="text/javascript">
+    let G_OFFSET_X = 0, G_OFFSET_Y = 0;
     function loading() {
         if (sessionStorage.multiRptsData) {
             let multiRptData = JSON.parse(sessionStorage.multiRptsData);
@@ -46,7 +47,7 @@
                 if (idx === 0) {
                     $(document).attr("title", pageData[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
                 }
-                let svgArr = rptPrintHelper.buildSvgArr(pageData, -30, -30);
+                let svgArr = rptPrintHelper.buildSvgArr(pageData, G_OFFSET_X, G_OFFSET_Y);
                 //let orientation = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] < pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?"纵向":"横向";
                 let orientation = "纵向";
                 showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, orientation);
@@ -55,7 +56,7 @@
         } else if (sessionStorage.currentPageData) {
             let pageData = JSON.parse(sessionStorage.currentPageData);
             let scaleFactor = parseInt(sessionStorage.scaleFactor);
-            let svgArr = rptPrintHelper.buildSvgArr(pageData, -30, -30);
+            let svgArr = rptPrintHelper.buildSvgArr(pageData, G_OFFSET_X, G_OFFSET_Y);
             $(document).attr("title", pageData[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
             //showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, sessionStorage.orientation);
             showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, "纵向");

+ 14 - 157
web/building_saas/report/js/rpt_print.js

@@ -60,7 +60,7 @@ let rptPrintHelper = {
         let isHtoV = false;
         if (pixelSize[0] > pixelSize[1]) {
             // changeHtoV(pagesData, pixelSize);
-            // isHtoV = true;
+            isHtoV = true;
         }
         for (let idx = 0; idx < pagesData.items.length; idx++) {
             let page = pagesData.items[idx];
@@ -69,7 +69,7 @@ let rptPrintHelper = {
             // let adjustY = 0.5 * ((idx + 1) % 2);
             let adjustY = 0.5;
             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, adjustY, canvas, isHtoV));
+                svgPageArr.push(buildCellSvg(cell, fonts, styles, controls, page[JV.PROP_PAGE_MERGE_BORDER], pagesData[JV.BAND_PROP_MERGE_BAND], offsetX, offsetY, adjustY, canvas, isHtoV, pixelSize));
             }
             svgPageArr.push("</svg>");
             rst.push(svgPageArr);
@@ -78,36 +78,6 @@ let rptPrintHelper = {
     }
 };
 
-function changeHtoV(pagesData, pixelSize) {
-    //坐标从横向变纵向
-    if (pixelSize[0] > pixelSize[1]) {
-        let tmpP = pixelSize[0];
-        pixelSize[0] = pixelSize[1];
-        pixelSize[1] = tmpP;
-    }
-    let offsetX = pixelSize[0];
-    // let RotAngF = (90 * Math.PI / 180); //这里默认就是90度旋转
-    let sinVal = 1; //sin 90度 = 1 不用算了
-    let cosVal = 0; //cos 90度 = 0 不用算了
-    for (let page of pagesData.items) {
-        for (let cell of page.cells) {
-            rotateCellArea(cell[JV.PROP_AREA], sinVal, cosVal, offsetX);
-        }
-    }
-}
-
-function rotateCellArea(area, sinVal, cosVal, offsetX) {
-    let Nx, Ny;
-    Nx = (area[JV.PROP_LEFT] * cosVal - area[JV.PROP_TOP] * sinVal);
-    Ny = (area[JV.PROP_TOP] * cosVal + area[JV.PROP_LEFT] * sinVal);
-    area[JV.PROP_LEFT] = Nx + offsetX;
-    area[JV.PROP_TOP] = Ny;
-    Nx = (area[JV.PROP_RIGHT] * cosVal - area[JV.PROP_BOTTOM] * sinVal);
-    Ny = (area[JV.PROP_BOTTOM] * cosVal + area[JV.PROP_RIGHT] * sinVal);
-    area[JV.PROP_RIGHT] = Nx + offsetX;
-    area[JV.PROP_BOTTOM] = Ny;
-}
-
 function getActualBorderStyle(cell, styles, mergeBorderStyle, pageBorderArea, borderStr) {
     let rst = styles[cell[JV.PROP_STYLE]][borderStr];
     if (mergeBorderStyle) {
@@ -128,7 +98,7 @@ function getActualBorderStyle(cell, styles, mergeBorderStyle, pageBorderArea, bo
     return rst;
 }
 
-function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY, adjustY, canvas, isHtoV) {
+function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY, adjustY, canvas, isHtoV, pixelSize) {
     let rst = [];
     let style = styles[cell[JV.PROP_STYLE]];
     let mergeBandStyle = null;
@@ -144,163 +114,50 @@ function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBo
         top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + adjustY,
         bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + adjustY
     ;
+    let HtoVStr = "";
+    if (isHtoV) {
+        HtoVStr = ` transform="translate(`+ pixelSize[1] + `,0) rotate(90)"`;
+    }
     if (style) {
         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:" + leftBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + leftBS[JV.PROP_LINE_WEIGHT] + "'" + HtoVStr + "/>")
         }
         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:" + rightBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + rightBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
         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:" + topBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + topBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
         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:" + bottomBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + bottomBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
     }
     let control = cell[JV.PROP_CONTROL];
     if (typeof control === 'string') {
         control = controls[cell[JV.PROP_CONTROL]];
     }
-    buildText(rst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV);
+    buildText(rst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV, HtoVStr);
 
     return rst.join("");
 }
 
-function buildTextHtoV(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV) {
-    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 fontStyle = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"normal";
-    let fontUnderline = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_UNDERLINE]] === 'T')?"underline":"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";
-            x = left + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "right") {
-            text_anchor = "end";
-            x = right - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "center") {
-            text_anchor = "middle";
-            x = Math.round((left + right) / 2);
-        }
-    }
-
-    let area = [0,0,0,0];
-    area[JV.IDX_TOP] = top;
-    area[JV.IDX_BOTTOM] = bottom;
-    area[JV.IDX_LEFT] = left;
-    area[JV.IDX_RIGHT] = right;
-    let height = bottom - top;
-    let ctx = canvas.getContext("2d");
-    let inner_draw_text = function (textValue) {
-        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];
-        function inner_build_text(innerTxt, innerArea) {
-            let innerDftFontHeight = (dftFontHeight * 3 / 4); //SVG的字体与canvas的字体大小的切换, 不用考虑取整
-            if (control) {
-                if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "top") {
-                    y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP];
-                } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "bottom") {
-                    y = innerArea[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
-                } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "center") {
-                    y = Math.round((innerArea[JV.IDX_TOP] + innerArea[JV.IDX_BOTTOM] + innerDftFontHeight) / 2 );
-                }
-            } else {
-                y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP];
-            }
-            if (font[JV.PROP_NAME] === "宋体") {
-                y--;
-            }
-            destRst.push("<text style='fill:black;font-family:" + font[JV.PROP_NAME] +
-                ";font-weight:" + fontWeight +
-                ";font-style:" + fontStyle +
-                ";text-decoration:" + fontUnderline +
-                // ";text-decoration:normal" +
-                ";font-size:" + innerDftFontHeight + "pt' x='" +
-                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'>" + innerTxt + "</text>");
-        }
-        let actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]), ctx);
-        if (actLines.length === 1 || (control && control.Shrink !== 'T')) {
-            inner_build_text(textValue, area);
-        } else {
-            while (true) {
-                if (dftFontHeight > 6) {
-                    let lines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + 4));
-                    lines = (lines === 0)?1:lines;
-                    actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]), ctx);
-                    if (lines >= actLines.length) {
-                        let aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + 4;
-                        if ((aH * actLines.length) < (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) && (control && control.Vertical !== 'top')) {
-                            if (control.Vertical === 'bottom') {
-                                area[JV.IDX_TOP] = area[JV.IDX_BOTTOM] - (aH * actLines.length);
-                            } else {
-                                area[JV.IDX_TOP] = (area[JV.IDX_TOP] + area[JV.IDX_BOTTOM]) / 2 - (aH * actLines.length) / 2
-                                area[JV.IDX_BOTTOM] = area[JV.IDX_TOP] + (aH * actLines.length);
-                            }
-                        }
-                        let newArea = [], baseTop = area[JV.IDX_TOP];
-                        for (let ai = 0; ai < area.length; ai++) {
-                            newArea[ai] = area[ai];
-                        }
-                        for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
-                            newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
-                            newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
-                            inner_build_text(actLines[lIdx], newArea);
-                        }
-                        break;
-                    } else {
-                        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 {
-                    inner_build_text(textValue, area);
-                    break;
-                }
-            }
-        }
-    };
-    for (let vidx = 0; vidx < values.length; vidx++) {
-        area[JV.IDX_TOP] = top + vidx * (height / values.length);
-        area[JV.IDX_BOTTOM] = top + (vidx + 1) * (height / values.length);
-        inner_draw_text(values[vidx]);
-    }
-}
-
-function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV) {
+function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV, HtoVStr) {
     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 fontStyle = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"normal";
@@ -368,7 +225,7 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
                 ";text-decoration:" + fontUnderline +
                 // ";text-decoration:normal" +
                 ";font-size:" + innerDftFontHeight + "pt' x='" +
-                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'>" + innerTxt + "</text>");
+                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'" + HtoVStr + ">" + innerTxt + "</text>");
         }
         let actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]), ctx);
         if (actLines.length === 1 || (control && control.Shrink !== 'T')) {