瀏覽代碼

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

zhongzewei 6 年之前
父節點
當前提交
a9870f77fd
共有 32 個文件被更改,包括 468 次插入114 次删除
  1. 1 1
      Dockerfile
  2. 56 0
      lib/rabbitmq/RabbitMQ.js
  3. 27 21
      logs/online_logs.js
  4. 4 1
      modules/all_models/compleRation_ration.js
  5. 5 3
      modules/all_models/project_glj.js
  6. 5 1
      modules/all_models/ration.js
  7. 4 1
      modules/all_models/stdRation_ration.js
  8. 40 16
      modules/complementary_ration_lib/models/searchModel.js
  9. 17 2
      modules/main/facade/ration_facade.js
  10. 54 6
      modules/ration_glj/facade/glj_calculate_facade.js
  11. 32 0
      modules/reports/rpt_component/jpc_event.js
  12. 2 0
      modules/reports/rpt_component/jpc_ex.js
  13. 20 4
      modules/reports/rpt_component/jpc_flow_tab.js
  14. 58 37
      modules/reports/util/rpt_pdf_util.js
  15. 47 2
      modules/reports/util/rpt_yanghu_data_util.js
  16. 1 1
      modules/users/controllers/boot_controller.js
  17. 1 0
      modules/users/controllers/login_controller.js
  18. 23 0
      public/cipher.js
  19. 28 0
      public/web/gljUtil.js
  20. 6 1
      public/web/rpt_value_define.js
  21. 12 8
      test/unit/reports/test_rpt_test_template.js
  22. 二進制
      web/building_saas/img/FirstPageSimple.cur
  23. 二進制
      web/building_saas/img/LastPageSimple.cur
  24. 二進制
      web/building_saas/img/NextPageSimple.cur
  25. 二進制
      web/building_saas/img/PreviousPageSimple.cur
  26. 1 1
      web/building_saas/main/js/models/calc_program.js
  27. 3 1
      web/building_saas/main/js/models/project_glj.js
  28. 3 0
      web/building_saas/main/js/models/ration.js
  29. 1 1
      web/building_saas/main/js/views/project_view.js
  30. 1 0
      web/building_saas/main/js/views/std_ration_lib.js
  31. 14 5
      web/building_saas/report/js/jpc_output.js
  32. 2 1
      web/building_saas/report/js/rpt_print.js

+ 1 - 1
Dockerfile

@@ -14,6 +14,6 @@ EXPOSE 2060
 
 ENV NODE_ENV=prod
 
-ENTRYPOINT babel-node server.js
+ENTRYPOINT babel-node --max-old-space-size=2048  server.js
 
 

+ 56 - 0
lib/rabbitmq/RabbitMQ.js

@@ -0,0 +1,56 @@
+/**
+ * Created by zhang on 2019/5/5.
+ */
+let amqp = require('amqplib');
+class RabbitMQ{
+    constructor(connect){
+        this.connect = connect;
+    }
+
+    static async connection(URL){
+        if(!RabbitMQ.instance){
+            RabbitMQ.instance =  new RabbitMQ(await amqp.connect(URL)) //'amqp://13726297388:123456@qa.smartcost.com.cn:5672'
+        }
+        return RabbitMQ.instance
+    }
+
+    static async sendMessage(queue,msg,durable=false){
+        if(RabbitMQ.instance){
+            let ch = await RabbitMQ.instance.connect.createChannel();
+            try {
+                await ch.assertQueue(queue, {durable: durable});
+                ch.sendToQueue(queue,Buffer.from(msg),{persistent: durable});
+                console.log(" Sent %s to :"+queue, msg);
+                ch.close();
+            }catch (e){
+                console.log(e);
+                ch.close();
+            }
+
+        }
+    }
+
+    static async receiveMessage(queue,callback,durable=false){
+        if(RabbitMQ.instance){
+            let ch = await RabbitMQ.instance.connect.createChannel();
+            try {
+                await ch.assertQueue(queue, {durable: durable});
+                ch.prefetch(1);
+                console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue);
+                ch.consume(queue, function(msg) {
+                    console.log(" [x] Received %s", msg.content.toString());
+                    if(durable == true) ch.ack(msg);
+                    if(callback) callback(msg)
+                }, {
+                    noAck: !durable
+                });
+            }catch (e){
+                console.log(e);
+                ch.close();
+            }
+        }
+    }
+}
+
+export default RabbitMQ;
+

+ 27 - 21
logs/online_logs.js

@@ -10,28 +10,34 @@ import moment from "moment";
 let logs_model = mongoose.model("online_logs");
 
 async function saveOnlineTime(req) {
-    let interval_time = 10 * 60 *1000;
-    let start = req.session.online_start_time;
+    let online_times = 0;
     let end = + new Date();
-    if(start === undefined) return req.session.online_start_time ==end;
-    let online_times =  end - start;
-    //1秒内只记一次就好
-    if(online_times < 500) return;//如果间隔太短,则忽略
-    if(online_times > interval_time ){//如果间隔超过有效时长,则不累加这次时长,从头开始算
-        req.session.online_start_time = end;
-        return
-    }
-    if(!req.session.sessionUser||!req.session.sessionCompilation) return;
-    let dataString = moment(end).format('YYYY-MM-DD');
-    let condition = {userID:req.session.sessionUser.id,compilationID:req.session.sessionCompilation._id,dateString:dataString};
-    let record = await logs_model.findOne(condition);
-    if(record){ //如果找到,则累加
-        await logs_model.update(condition,{$inc:{'online_times' : online_times }});
-    }else {//如果没找到,则新增一条记录
-        condition["online_times"] = online_times;
-        let today = moment(dataString).toDate();
-        condition["dateTime"] = +today;
-        await logs_model.create(condition);
+    try {
+        let interval_time = 10 * 60 *1000;
+        let start = req.session.online_start_time;
+        if(start === undefined) return req.session.online_start_time ==end;
+        online_times =  end - start;
+        //1秒内只记一次就好
+        if(online_times < 500) return;//如果间隔太短,则忽略
+        if(online_times > interval_time ){//如果间隔超过有效时长,则不累加这次时长,从头开始算
+            req.session.online_start_time = end;
+            return
+        }
+        if(!req.session.sessionUser||!req.session.sessionCompilation) return;
+        let dataString = moment(end).format('YYYY-MM-DD');
+        let condition = {userID:req.session.sessionUser.id,compilationID:req.session.sessionCompilation._id,dateString:dataString};
+        let record = await logs_model.findOne(condition);
+        if(record){ //如果找到,则累加
+            await logs_model.update(condition,{$inc:{'online_times' : online_times }});
+        }else {//如果没找到,则新增一条记录
+            condition["online_times"] = online_times;
+            let today = moment(dataString).toDate();
+            condition["dateTime"] = +today;
+            await logs_model.create(condition);
+        }
+    }catch (e){
+        console.log("统计登录时间错误,online_times值:"+online_times);
+        console.log(e)
     }
     req.session.online_start_time = end;
 }

+ 4 - 1
modules/all_models/compleRation_ration.js

@@ -24,7 +24,10 @@ const compleRationAssItemSchema = new Schema({
     decimal: Number,
     carryBit: String,
     minValue: String,
-    maxValue: String
+    maxValue: String,
+    paramName:String,//参数名称
+    param:String,//参数
+    thirdRationCode:String//第三定额
 }, { _id: false });
 
 //定额安装增加费用

+ 5 - 3
modules/all_models/project_glj.js

@@ -84,9 +84,9 @@ let modelSchema = {
     // 显示关联单价文件的字段
     unit_price: Schema.Types.Mixed,
     // 显示关联的消耗量
-    quantity: String,
-    techQuantity:String,//技术措施项目消耗量
-    subdivisionQuantity:String,//分部分项消耗量
+    quantity: Number,
+    techQuantity:Number,//技术措施项目消耗量
+    subdivisionQuantity:Number,//分部分项消耗量
     // 不调价
     tenderPrice: String,//调整后价格
     // 显示组成物的消耗量
@@ -103,6 +103,8 @@ let modelSchema = {
         default: 1
     },
     from:{type: String,default:'std'},//std, cpt  来自标准工料机库、补充工料机库
+    offSiteTransportLossRate: Number, //场外运输损耗率(实际)
+    transportLossQuantity: Number,    //场外运输损耗量(实际)
     //以下仅普通材料可用
     ratio_data: Schema.Types.Mixed,
     remark:String

+ 5 - 1
modules/all_models/ration.js

@@ -17,7 +17,11 @@ var rationAssItemSchema = mongoose.Schema({
     carryBit: String,
     minValue: String,
     maxValue: String,
-    isAdjust:Number //0不调整,1调整
+    paramName:String,//参数名称
+    param:String,//参数
+    thirdRationCode:String,//第三定额
+    isAdjust:Number,//0不调整,1调整
+    groupList:[Schema.Types.Mixed]//当有分组的时候用这个
 }, { _id: false });
 
 // 定额、量价、工料机定额 合并存储

+ 4 - 1
modules/all_models/stdRation_ration.js

@@ -19,7 +19,10 @@ const rationAssItemSchema = new Schema({
     decimal: Number,
     carryBit: String,
     minValue: String,
-    maxValue: String
+    maxValue: String,
+    paramName:String,//参数名称
+    param:String,//参数
+    thirdRationCode:String//第三定额
 }, { _id: false });
 
 //定额安装增加费用

+ 40 - 16
modules/complementary_ration_lib/models/searchModel.js

@@ -15,27 +15,30 @@ class SearchDao{
     async getRationItem(userId, compilationId, rationRepIds, code, ID, callback){
         let ration = null;
         try{
+            let firstLib = rationRepIds.shift();//优先取第一个
+            if(rationRepIds.includes(firstLib)) {//去掉重复的库ID
+                rationRepIds.splice(rationRepIds.indexOf(firstLib), 1);
+            }
             if(rationRepIds.includes(compleRationLib)) {
                 rationRepIds.splice(rationRepIds.indexOf(compleRationLib), 1);
             }
-            let stdQuery = {rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]};
-            if(ID){
-                stdQuery = {ID: ID, $or: [{isDeleted: null}, {isDeleted: false}]};
-            }
-            let stdRation = await stdRationModel.findOne(stdQuery);
-            if(isDef(stdRation)){
-                ration = stdRation._doc;
-                ration.type = 'std';
-            } else{
-                let compleQuery = {userId: userId, compilationId: compilationId, code: code, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]};
+            if(firstLib == compleRationLib){//说明选中的是补充定额库
+                ration = await this.getCompleRation(userId,compilationId,code,ID);
+            }else {
+                firstLib = parseInt(firstLib);
+                let firstQuery = {rationRepId: firstLib, code: code, $or: [{isDeleted: null}, {isDeleted: false}]};
                 if(ID){
-                    compleQuery.ID = ID;
+                    firstQuery = {ID: ID, $or: [{isDeleted: null}, {isDeleted: false}]};
                 }
-                let compleRation = await compleRationModel.findOne(compleQuery);
-                if(isDef(compleRation)){
-                    ration = compleRation._doc;
-                    ration.type = 'complementary';
+                ration = await this.getStdRation(firstQuery);
+            }
+            if(ration == null){//选中的定额库或者默认的定额库中没有找到定额,才走常规的流程查找其它定额库
+                let stdQuery = {rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]};
+                if(ID){
+                    stdQuery = {ID: ID, $or: [{isDeleted: null}, {isDeleted: false}]};
                 }
+                ration = await this.getStdRation(stdQuery);
+                if(ration == null) ration = await this.getCompleRation(userId,compilationId,code,ID);
             }
             if(isDef(ration)){
                 if (ration.type === 'std') {
@@ -61,7 +64,28 @@ class SearchDao{
         }
         return ration;
     }
-
+    async getCompleRation(userId,compilationId,code,ID){
+        let ration = null;
+        let compleQuery = {userId: userId, compilationId: compilationId, code: code, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]};
+        if(ID){
+            compleQuery.ID = ID;
+        }
+        let compleRation = await compleRationModel.findOne(compleQuery);
+        if(isDef(compleRation)){
+            ration = compleRation._doc;
+            ration.type = 'complementary';
+        }
+        return ration
+    }
+    async getStdRation(query){
+        let ration = null;
+        let stdRation = await stdRationModel.findOne(query);
+        if(isDef(stdRation)){
+            ration = stdRation._doc;
+            ration.type = 'std';
+        }
+        return ration;
+    }
     //@param {Object}skip({std: Number, comple: Number})
     async findRation(userId, compilationId, rationRepId, keyword, skip, callback){
         //每次限制结果数

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

@@ -594,13 +594,28 @@ async function setEmptyRation(projectID,rationID){
 function createRationAss(std) {
     let  rationAssList = [];//生成辅助定额
     if(std.hasOwnProperty('rationAssList')&&std.rationAssList.length>0){
-        for(let i=0;i<std.rationAssList.length;i++){
-            let ass = std.rationAssList[i];
+        let assGroup =  _.groupBy(std.rationAssList,'name');
+        for(let key in assGroup){
+            let assList = assGroup[key];
+            let ass = assList[0];
             ass._doc.actualValue = ass.stdValue;
             ass._doc.isAdjust = 0;
             if(_.isString(ass._doc.assistCode)) ass._doc.assistCode = ass._doc.assistCode.replace("\n","");
+            if(_.isString(ass._doc.thirdRationCode)) ass._doc.thirdRationCode = ass._doc.thirdRationCode.replace("\n","");
+            if(assList.length > 1){
+                ass._doc.groupList = JSON.parse(JSON.stringify(assList))  ;
+                ass._doc.maxValue = assList[assList.length-1]._doc.maxValue;
+            }
             rationAssList.push(ass);
         }
+      /*  for(let i=0;i<std.rationAssList.length;i++){
+            let ass = std.rationAssList[i];
+            ass._doc.actualValue = ass.stdValue;
+            ass._doc.isAdjust = 0;
+            if(_.isString(ass._doc.assistCode)) ass._doc.assistCode = ass._doc.assistCode.replace("\n","");
+            if(_.isString(ass._doc.thirdRationCode)) ass._doc.thirdRationCode = ass._doc.thirdRationCode.replace("\n","");
+            rationAssList.push(ass);
+        }*/
     }
     return rationAssList;
 }

+ 54 - 6
modules/ration_glj/facade/glj_calculate_facade.js

@@ -56,14 +56,30 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
              return null;
          }
          if(impactRation._doc.hasOwnProperty("rationAssList")&&impactRation.rationAssList.length>0){
+             prepareAss(impactRation.rationAssList);
+             let temTimes = [];
+             let thirdRationCodes=[];
              for(let i=0;i<impactRation.rationAssList.length;i++){
                  let times = calculateTimes(impactRation.rationAssList[i]);
                  if(times!=0){
+                     let thirdRationCode = impactRation.rationAssList[i].thirdRationCode;
+                     if(thirdRationCode && thirdRationCode !=''){
+                         temTimes.push(times);
+                         thirdRationCodes.push(thirdRationCode)
+                     }
                      assRation = await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:impactRation.rationAssList[i].assistCode});
                      assList.push({times:times,assRation:assRation});
                      adjustState.push({index:stateSeq.ass,content:impactRation.rationAssList[i].name+" "+impactRation.rationAssList[i].actualValue+" : +"+impactRation.rationAssList[i].assistCode+"x"+times});
                  }
              }
+             if(temTimes.length == 2 &&thirdRationCodes[0] == thirdRationCodes[1] ){ //说明有第三定额
+                 let times_t = temTimes[0] * temTimes[1];
+                 let tration =  await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:thirdRationCodes[0]});
+                 if(tration){
+                     assList.push({times:times_t,assRation:tration});
+                     adjustState.push({index:stateSeq.ass,content:"+"+thirdRationCodes[0]+"x"+times_t});
+                 }
+             }
          }
          for(let glj of gljList){//先把混凝土,砂浆,配合比有自定义消耗的挑出来
              if(gljUtil.isConcreteType(glj.type)) await getMixRatioMap(glj,gljList,coeList,assList,mixRatioMap);
@@ -96,12 +112,26 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
 
 function generateRationName(ration,gljList) {
     let caption = ration.caption ? ration.caption:ration.name;
-    if(ration.rationAssList && ration.rationAssList.length > 0){
-        let ass = ration.rationAssList[0];
-        if( ass.isAdjust == 1 && ass.actualValue != null && ass.actualValue != undefined ){
-            caption =  caption.replace('%s',ass.actualValue);
-        }else {
-            caption =  caption.replace('%s',ass.stdValue);//没勾选的时候要恢复成标准值
+    let replaceList = [];
+    if(ration.rationAssList && ration.rationAssList.length > 0){//这里要处理第三定额和多辅助定额的情况
+        let isThird = ration.rationAssList.length == 2 && ration.rationAssList[0].thirdRationCode&&ration.rationAssList[0].thirdRationCode!='';//说明有第三定额的情况
+        let adjustMatch = "",notAdjust="";
+        for(let ass of ration.rationAssList){
+            let tem = "";
+            if( ass.isAdjust == 1 && ass.actualValue != null && ass.actualValue != undefined ){
+                tem = ass.actualValue;
+                adjustMatch = tem;
+            }else {
+                tem = ass.stdValue;
+                notAdjust = tem;
+            }
+            if(isThird) replaceList.push(tem);
+        }
+        if(replaceList.length == 0){
+            adjustMatch!=""?replaceList.push(adjustMatch):replaceList.push(notAdjust);
+        }
+        for(let r of replaceList){
+            caption =  caption.replace('%s',r);
         }
     }
     let reNameList = [];
@@ -348,6 +378,22 @@ function getContent(coes) {
 
 }
 
+function prepareAss(assList) {//处理辅助定额,支持多个辅助定额的情况
+    for(let a of assList){
+        if(a.groupList && a.groupList.length > 1){//组里有多个定额的情况
+            let newList = _.sortByAll(a.groupList,['param']);//先按参数排序
+            for(let n of newList){
+                if(a.actualValue > n.stdValue && a.actualValue <= parseFloat(n.param)){//落在中间,则用组里的这条定额
+                    a._doc.param = n.param;
+                    a._doc.paramName = n.paramName;
+                    a._doc.assistCode = n.assistCode;
+                    break;
+                }
+            }
+        }
+    }
+}
+
 function calculateTimes(ass){
     if(ass.isAdjust == 0) return 0;//打勾辅助定额才计算
     let times =(ass.actualValue-ass.stdValue)/ass.stepValue;
@@ -360,6 +406,8 @@ function calculateTimes(ass){
         times = _.round(times,ass.decimal);
     }else if (ass.carryBit=='进一'){
         times =_.ceil(times,ass.decimal);
+    }else if(ass.carryBit == '舍一'){
+        times = _.floor(times,ass.decimal);
     }
     if(r){
         times=times*-1;

+ 32 - 0
modules/reports/rpt_component/jpc_event.js

@@ -0,0 +1,32 @@
+/**
+ * Created by Tony on 2019/5/17.
+ */
+let JV = require('./jpc_value_define');
+let JpcEvent = {
+    createNew: function (rptTpl) {
+        let rst = {};
+        if (rptTpl[JV.NODE_EVENTS]) {
+            for (let i = 0; i < rptTpl[JV.NODE_EVENTS].length; i++) {
+                let item = {};
+                let propArr = Object.getOwnPropertyNames(rptTpl[JV.NODE_EVENTS][i]);
+                for (let key of propArr) {
+                    item[key] = rptTpl[JV.NODE_EVENTS][i][key];
+                }
+                switch (JV.EVENT_TYPE.indexOf(item.type)) {
+                    case JV.EVENT_IDX_GRP_ON_CREATE:
+                        rst[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]] = item;
+                        break;
+                    case JV.EVENT_IDX_FLOW_CONTENT_ON_CREATE:
+                        rst[JV.EVENT_TYPE[JV.EVENT_IDX_FLOW_CONTENT_ON_CREATE]] = item;
+                        break;
+                    default :
+                        break;
+                }
+                //rst.push(item);
+            }
+        }
+        return rst;
+    }
+};
+
+module.exports = JpcEvent;

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

@@ -6,6 +6,7 @@ let JpcCrossTab = require('./jpc_cross_tab');
 let JpcField = require('./jpc_field');
 let JpcParam = require('./jpc_param');
 let JpcFunc = require('./jpc_function');
+let JpcEvent = require('./jpc_event');
 let JpcData = require('./jpc_data');
 let JpcCommonHelper = require('./helper/jpc_helper_common');
 let $JE = require('./jpc_rte'); //Important: for self-define function execution purpose
@@ -162,6 +163,7 @@ JpcExSrv.prototype.createNew = function(){
         me.fields = JpcField.createNew(rptTpl);
         me.params = JpcParam.createNew(rptTpl);
         me.formulas = JpcFunc.createNew(rptTpl);
+        me.events = JpcEvent.createNew(rptTpl);
     };
 
     JpcResult.analyzeData = function(rptTpl, dataObj, defProperties, option, outputType) {

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

@@ -1115,6 +1115,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 me.pageSumValLst.push(rowGrandTotal);
                 //grouping content
+                let grpVal_Idx = 0;
                 for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
                     if (contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_GROUP) {
                         for (let grpIdx = 0; grpIdx < rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length; grpIdx++) {
@@ -1130,7 +1131,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                         }
                                     }
                                 }
-                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx);
+                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx, grpVal_Idx, $CURRENT_RPT);
+                                grpVal_Idx++;
                                 rst = rst.concat(lineRst);
                             }
                         }
@@ -1276,7 +1278,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             return rst;
         }
     };
-    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx) {
+    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx, grpVal_Idx, $CURRENT_RPT) {
         let me = this, rst = [];
         if (grp_line[JV.PROP_GROUP_SUM_KEYS]) {
             let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
@@ -1289,8 +1291,13 @@ JpcFlowTabSrv.prototype.createNew = function(){
             }
         }
         if (grp_line[JV.PROP_TEXTS]) {
-            for (let txt of grp_line[JV.PROP_TEXTS]) {
-                rst.push(JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx));
+            for (let grpIdx = 0; grpIdx < grp_line[JV.PROP_TEXTS].length; grpIdx++) {
+                let txt = grp_line[JV.PROP_TEXTS][grpIdx];
+                let rstCell = JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx);
+                if ($CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]) {
+                    me.eventGrpOnCreate(rstCell, JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE], grpIdx, grpVal_Idx, $CURRENT_RPT);
+                }
+                rst.push(rstCell);
             }
         }
         if (grp_line[JV.PROP_DISCRETE_FIELDS]) {
@@ -1302,6 +1309,15 @@ JpcFlowTabSrv.prototype.createNew = function(){
         // console.log(rst);
         return rst;
     };
+    JpcFlowTabResult.eventGrpOnCreate = function (_$CELL, _$GRP_TYPE, _$GRP_OBJ_IDX, _$GRP_VAL_IDX, $CURRENT_RPT) {
+        if ($CURRENT_RPT.events && $CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]) {
+            try {
+                eval($CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]);
+            } catch (ex) {
+                console.log(ex);
+            }
+        }
+    };
     JpcFlowTabResult.commonTabRestOutput = function(dataObj, page, segIdx, bands, band, unitFactor, tab, multiColIdx){
         let me = this, rst = [];
         if (tab[JV.PROP_TEXT]) {

+ 58 - 37
modules/reports/util/rpt_pdf_util.js

@@ -5,11 +5,12 @@
  * Created by zhang on 2017/8/14.
  */
 
-let pdf = require('pdfkit');
-let fs = require('fs');
-let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
-let DPI = jpcCmnHelper.getScreenDPI()[0];
-let JV = require('../rpt_component/jpc_value_define');
+const pdf = require('pdfkit');
+const PDF_SCALE = 0.75;
+const fs = require('fs');
+const jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
+const DPI = jpcCmnHelper.getScreenDPI()[0] * PDF_SCALE;
+const JV = require('../rpt_component/jpc_value_define');
 const uuidV1 = require('uuid/v1');
 
 let fontUtil = require('./rpt_font_util');
@@ -106,10 +107,12 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
                 destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
             }
         }
-        doc.moveTo(cell[JV.PROP_AREA][startP[0]] + offsetX, cell[JV.PROP_AREA][startP[1]] + offsetY);
+        // doc.moveTo(cell[JV.PROP_AREA][startP[0]] + offsetX, cell[JV.PROP_AREA][startP[1]] + offsetY);
+        doc.moveTo( (cell[JV.PROP_AREA][startP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][startP[1]] + offsetY) * PDF_SCALE);
         if (destStyle[styleBorderDest] && parseFloat(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) !== 0) {
             doc.lineWidth(1.0 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]);
-            doc.lineTo(cell[JV.PROP_AREA][destP[0]] + offsetX, cell[JV.PROP_AREA][destP[1]] + offsetY);
+            // doc.lineTo(cell[JV.PROP_AREA][destP[0]] + offsetX, cell[JV.PROP_AREA][destP[1]] + offsetY);
+            doc.lineTo((cell[JV.PROP_AREA][destP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][destP[1]] + offsetY) * PDF_SCALE);
             doc.strokeColor(destStyle[styleBorderDest][JV.PROP_COLOR]);
         }
         doc.stroke();
@@ -181,34 +184,39 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
             }
         };
         inner_setupControl(area, dftFontHeight, output);
-        let w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+        let validAreaTxtWidth = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+        let validTxtLines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
         if (parseInt(font.FontAngle) !== 0) {
-            w = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+            validAreaTxtWidth = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+            validTxtLines = Math.floor((area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] + 4));
         }
 
-        function private_drawUnderline() {
+        function private_drawUnderline(underLineVal, underLineArea) {
             //A. 暂不支持角度; B. PDF输出时,坐标没有translate
             let ctx = doc;
             //1. 计算下划线的相关坐标
-            let width = ctx.widthOfString(val);
+            let width = ctx.widthOfString(underLineVal);
+            if (width > underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT]) {
+                width = underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT];
+            }
             let height = dftFontHeight;
-            let startX = area[JV.IDX_LEFT], startY = area[JV.IDX_TOP], endX = area[JV.IDX_RIGHT], endY = area[JV.IDX_BOTTOM];
+            let startX = underLineArea[JV.IDX_LEFT], startY = underLineArea[JV.IDX_TOP], endX = underLineArea[JV.IDX_RIGHT], endY = underLineArea[JV.IDX_BOTTOM];
             // let startX = 0, startY = 0, endX = width, endY = startY;
             if (control.Horizon === "left") {
-                startX = Math.round(area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
+                startX = Math.round(underLineArea[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
             } else if (control.Horizon === "right") {
-                startX = Math.round(area[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
+                startX = Math.round(underLineArea[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
             } else {
-                startX = Math.round( area[JV.IDX_LEFT] + (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT] - width) / 2);
+                startX = Math.round( underLineArea[JV.IDX_LEFT] + (underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT] - width) / 2);
             }
             endX = Math.round(startX + width);
 
             if (control.Vertical === "top") {
-                startY = Math.round(area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height);
+                startY = Math.round(underLineArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height);
             } else if (control.Vertical === "bottom") {
-                startY = Math.round(area[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
+                startY = Math.round(underLineArea[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
             } else {
-                startY = Math.round( area[JV.IDX_TOP] + (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP] + height) / 2) + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                startY = Math.round( underLineArea[JV.IDX_TOP] + (underLineArea[JV.IDX_BOTTOM] - underLineArea[JV.IDX_TOP] + height) / 2) + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
             }
             endY = Math.round(startY);
             //2. 画线
@@ -217,42 +225,50 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
                 ctx.translate(0,0.5);
             }
             // ctx.beginPath();
-            ctx.moveTo(startX, startY);
+            // ctx.moveTo(startX, startY);
+            ctx.moveTo(startX * PDF_SCALE, startY * PDF_SCALE);
             ctx.lineWidth(1);
             ctx.strokeStyle = "BLACK";
-            ctx.lineTo(endX, endY);
+            // ctx.lineTo(endX, endY);
+            ctx.lineTo(endX * PDF_SCALE, endY * PDF_SCALE);
             ctx.stroke();
             // ctx.restore();
         }
 
         let rotateOptions;
-        if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
-            private_drawUnderline();
-        }
+        // if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+        //     private_drawUnderline(val);
+        // }
         if (parseInt(font.FontAngle) !== 0) {
             if (control){
-                rotateOptions = private_setupAreaRotateOption(area,w,control.Vertical,dftFontHeight, output);
+                rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,control.Vertical,dftFontHeight, output);
             } else {
-                rotateOptions = private_setupAreaRotateOption(area,w,"bottom",dftFontHeight, output);
+                rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,"bottom",dftFontHeight, output);
             }
             doc.rotate(font.FontAngle,rotateOptions);
         }
-        if (w >= doc.widthOfString(val) || (control && control.Shrink !== 'T')) {
-            options.width = w;
-            options.height = dftFontHeight;
-            doc.text(val,output[0], output[1], options);
+        if (validAreaTxtWidth >= doc.widthOfString(val) ||
+            (control && control.Shrink !== 'T' && validTxtLines < private_splitString(val, validAreaTxtWidth, doc)) ) {
+            options.width = validAreaTxtWidth * PDF_SCALE;
+            options.height = dftFontHeight * PDF_SCALE;
+            doc.fontSize(dftFontHeight);
+            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                private_drawUnderline(val, area);
+            }
+            doc.fontSize(dftFontHeight * PDF_SCALE);
+            doc.text(val,output[0] * PDF_SCALE, output[1] * PDF_SCALE, options);
             doc.font(__dirname + '/pdf_base_files/simhei_bold_italic.ttf');
         } else {
             while (true) {
                 //*/
                 let lines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
                 lines = (lines === 0 || (control.Shrink === 'T' && control.ShrinkFirst === 'T'))?1:lines;
-                let actLines = private_splitString(val, w, doc);
+                let actLines = private_splitString(val, validAreaTxtWidth, doc);
                 if (actLines.length > lines && dftFontHeight >= 6) {
                     dftFontHeight--;
                     doc.fontSize(dftFontHeight);
-                    options.width = w;
-                    options.height = dftFontHeight;
+                    options.width = validAreaTxtWidth * PDF_SCALE;
+                    options.height = dftFontHeight * PDF_SCALE;
                     // doc.text(val,output[0], output[1], options);
                 } else {
                     let aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4;
@@ -268,21 +284,26 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
                     for (let ai = 0; ai < area.length; ai++) {
                         newArea[ai] = area[ai];
                     }
-                    options.width = w;
-                    options.height = dftFontHeight;
+                    options.width = validAreaTxtWidth * PDF_SCALE;
+                    options.height = dftFontHeight * PDF_SCALE;
                     for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
                         newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
                         newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
                         inner_setupControl(newArea, dftFontHeight, output);
-                        doc.text(actLines[lIdx], output[0], output[1], options);
+                        doc.fontSize(dftFontHeight);
+                        if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                            private_drawUnderline(actLines[lIdx], newArea);
+                        }
+                        doc.fontSize(dftFontHeight * PDF_SCALE);
+                        doc.text(actLines[lIdx], output[0] * PDF_SCALE, output[1] * PDF_SCALE, options);
                     }
                     break;
                 }
                 /*/
                 dftFontHeight--;
                 doc.fontSize(dftFontHeight);
-                if (w >= doc.widthOfString(val) || dftFontHeight < 6) {
-                    options.width = w;
+                if (validAreaTxtWidth >= doc.widthOfString(val) || dftFontHeight < 6) {
+                    options.width = validAreaTxtWidth;
                     options.height = dftFontHeight;
                     doc.text(val,output[0], output[1], options);
                     doc.font(__dirname + '/pdf_base_files/simhei_bold_italic.ttf');

+ 47 - 2
modules/reports/util/rpt_yanghu_data_util.js

@@ -326,7 +326,7 @@ class Rpt_Data_Extractor {
                         adjustData(srcData, preHandle);
                         break;
                     case JV.PROP_HANDLE_TYPE_BILLS_DATA_MOVE:
-                        //把显示在清单中的量材转移到工料机去
+                        //把显示在清单中的量材转移到工料机去, 顺带把项目工料机的组成物工料机分解出来,分解的工料机作为定额工料机保存(02表用)
                         moveRationData(srcData, rawDataObj);
                         break;
                     case JV.PROP_HANDLE_TYPE_COMPONENT_REPLACEMENT:
@@ -857,16 +857,61 @@ function moveRationData(rationData, rawDataObj) {
                     copyItem.projectGLJID = dummyPRJID;
                     dummyPrjItem.id = dummyPRJID;
                     dummyPRJID++;
+                    dummyPrjItem.name = rationItem.name;
                     dummyPrjItem.unit_price = {};
                     dummyPrjItem.unit_price.base_price = 0;
                     dummyPrjItem.unit_price.market_price = (rationItem["marketUnitFee"])?rationItem["marketUnitFee"]:0;
-                    dummyPrjItem.quantity = 0;
+                    dummyPrjItem.quantity = 1; //这里设置为1只是为了不被误过滤
                     dummyPrjItem.is_evaluate = 0;
                     prjGljData.data.gljList.push(dummyPrjItem);
                 }
                 rationGljData.data.push(copyItem);
+            } else {
+                //无
+            }
+        }
+        //这里考虑到项目工料机有组成物,那么这些组成物应该要归类到定额工料机下
+        let newComponentItem = [];
+        for (let rationGljItem of getActDataArr(rationGljData)) {
+            for (let prjGljItem of prjGljData.data.gljList) {
+                if (prjGljItem.id === rationGljItem.projectGLJID) {
+                    if (prjGljItem.ratio_data && prjGljItem.ratio_data.length > 0) {
+                        //有组成物
+                        for (let comItem of prjGljItem.ratio_data) {
+                            let copyItem = {};
+                            copyItem.ID = comItem._id.toString();
+                            copyItem.projectID = rationGljItem.projectID;
+                            copyItem.rationID = rationGljItem.rationID;
+                            // copyItem.rationItemQuantity = rationGljItem.quantity;
+                            copyItem.quantity = parseFloat(rationGljItem.quantity) * parseFloat(comItem.consumption);
+                            copyItem.name = comItem.name;
+                            copyItem.code = comItem.code;
+                            copyItem.unit = comItem.unit;
+                            copyItem.specs = comItem.specs;
+                            // copyItem.shortName = comItem.shortName;
+                            copyItem.billsItemID = rationGljItem.billsItemID;
+                            copyItem.type = comItem.type;
+                            //其他属性,要根据工料机ID来查找
+                            for (let gljIdx = 0; gljIdx < prjGljData.data.gljList.length; gljIdx++) {
+                                if (prjGljData.data.gljList[gljIdx].code === comItem.code) {
+                                    copyItem.projectGLJID = prjGljData.data.gljList[gljIdx].id;
+                                    copyItem.original_code = prjGljData.data.gljList[gljIdx].original_code;
+                                    copyItem.is_main_material = prjGljData.data.gljList[gljIdx].is_main_material;
+                                    copyItem.is_adjust_price = prjGljData.data.gljList[gljIdx].is_adjust_price;
+                                    copyItem.unit_price = {};
+                                    copyItem.unit_price.base_price = prjGljData.data.gljList[gljIdx].unit_price.base_price;
+                                    copyItem.unit_price.market_price = prjGljData.data.gljList[gljIdx].unit_price.market_price;
+                                    break;
+                                }
+                            }
+                            newComponentItem.push(copyItem);
+                        }
+                    }
+                    break;
+                }
             }
         }
+        rationGljData.data = rationGljData.data.concat(newComponentItem);
         // fsUtil.writeObjToFile(rationGljData.data, "D:/GitHome/ConstructionCost/tmp/afterMoveGLJ.jsp");
     }
 }

+ 1 - 1
modules/users/controllers/boot_controller.js

@@ -55,4 +55,4 @@ class BootController extends BaseController {
     }
 
 }
-export default BootController;
+export default BootController;

+ 1 - 0
modules/users/controllers/login_controller.js

@@ -99,6 +99,7 @@ class LoginController {
                     request.session.sessionCompilation = compilationData;
                     if(request.session.sessionUser.latest_used !== preferenceSetting.select_version) await userModel.updateLatestUsed(request.session.sessionUser.id,preferenceSetting.select_version);
                 }
+                request.session.online_start_time = +new Date();
                 console.log(`${request.session.sessionUser.real_name}--id:${request.session.sessionUser.id}--登录了系统`);
                 if (preferenceSetting.login_ask === 1 || preferenceSetting.select_version === '') {
                     let renderData = {

+ 23 - 0
public/cipher.js

@@ -0,0 +1,23 @@
+/**
+ * Created by zhang on 2019/5/10.
+ */
+let crypto = require('crypto');
+module.exports ={
+    aesEncrypt:aesEncrypt,
+    aesDecrypt:aesDecrypt
+};
+
+
+function aesEncrypt(data, key = 'SmartCost') {
+    const cipher = crypto.createCipher('aes192', key);
+    var crypted = cipher.update(data, 'utf8', 'hex');
+    crypted += cipher.final('hex');
+    return crypted;
+}
+
+function aesDecrypt(encrypted, key= 'SmartCost') {
+    const decipher = crypto.createDecipher('aes192', key);
+    var decrypted = decipher.update(encrypted, 'hex', 'utf8');
+    decrypted += decipher.final('utf8');
+    return decrypted;
+}

+ 28 - 0
public/web/gljUtil.js

@@ -46,6 +46,34 @@ let gljUtil = {
                 }
             }
         }
+        //计算经过场外运输损耗后的总消耗量
+        for(let pglj of project_gljs ){
+            let offSiteTransportLossRate = this.getOffSiteTransportLossRate(pglj);
+            pglj.offSiteTransportLossRate = parseFloat(offSiteTransportLossRate);//scMathUtil.roundForObj(offSiteTransportLossRate,getDecimal("glj.unitPrice")) ;这里再取小数位数太麻烦了,暂时用保存的吧
+            offSiteTransportLossRate = offSiteTransportLossRate/100;
+            pglj.transportLossQuantity =  scMathUtil.roundForObj(pglj.quantity*offSiteTransportLossRate,q_decimal);
+            pglj.quantity = scMathUtil.roundForObj(pglj.quantity +  pglj.transportLossQuantity ,q_decimal);
+        }
+    },
+    getOffSiteTransportLossRate:function (pglj) {
+        let offSiteTransportLossRate;//场外运输损耗率
+        let handlingLossRate;//每增加一次装卸损耗率
+        let totalLoadingTimes = 1;//没有材料计算,获取不到装卸总次数,则按1计算
+        //场外总损耗率=场外运输损耗率%+(装卸总次数-1)*每增加一次装卸损耗率%。
+        if(pglj.unit_price){
+            if(pglj.unit_price.calcMaterial == 1){//如果是材料计算,则用修改过的新值
+                offSiteTransportLossRate = pglj.unit_price.offSiteTransportLossRate_n;
+                handlingLossRate = pglj.unit_price.handlingLossRate_n;
+                if(pglj.unit_price.totalLoadingTimes && pglj.unit_price.totalLoadingTimes > 1) totalLoadingTimes = parseFloat(pglj.unit_price.totalLoadingTimes)
+            } else {
+                offSiteTransportLossRate = pglj.unit_price.offSiteTransportLossRate;
+                handlingLossRate = pglj.unit_price.handlingLossRate;
+            }
+        }
+        offSiteTransportLossRate = offSiteTransportLossRate?parseFloat(offSiteTransportLossRate):0;
+        handlingLossRate = handlingLossRate?parseFloat(handlingLossRate):0;
+       // 场外运输损耗率%+(装卸总次数-1)*每增加一次装卸损耗率%
+        return (offSiteTransportLossRate + (totalLoadingTimes - 1) * handlingLossRate);
     },
     getQuantityPerGLJ : function (ration_glj_list,rations,rationMap,pglj,billIDs,tech_billIDS,q_decimal,_,scMathUtil,isTender) {
         let result={};

+ 6 - 1
public/web/rpt_value_define.js

@@ -21,6 +21,7 @@ const JV = {
     NODE_DETAIL_FIELDS_EX: "从数据指标_拓展集合",
     NODE_BAND_COLLECTION: "布局框_集合",
     NODE_FORMULAS: "计算式_集合",
+    NODE_EVENTS: "事件_集合",
     NODE_DISCRETE_INFO: "离散信息",
     NODE_BILL_INFO: "账单式表_信息",
     NODE_BILL_CONTENT : "账单式表_数据",
@@ -67,7 +68,7 @@ const JV = {
     PROP_HANDLE_TYPE_SORT: "排序",
     PROP_HANDLE_TYPE_ADD_DUMMY: "增加Dummy数据",
     PROP_HANDLE_TYPE_ADJUST: "数据调整",
-    PROP_HANDLE_TYPE_BILLS_DATA_MOVE: "量材数据转移",
+    PROP_HANDLE_TYPE_BILLS_DATA_MOVE: "量材及组成物数据转移",
     PROP_HANDLE_TYPE_COMPONENT_REPLACEMENT: "组成物替换",
     PROP_HANDLE_TYPE_PRECISION: "合计精度",
 
@@ -261,6 +262,10 @@ const JV = {
     CAL_TYPE_PERCENTAGE: 0,
     CAL_TYPE_ABSTRACT: 1,
 
+    EVENT_TYPE: ["GRP_ON_CREATE", "FLOW_CONTENT_ON_CREATE"],
+    EVENT_IDX_GRP_ON_CREATE: 0,
+    EVENT_IDX_FLOW_CONTENT_ON_CREATE: 1,
+
     PAGE_ORIENTATION_V_FIRST: 0,
     PAGE_ORIENTATION_H_FIRST: 1,
 

+ 12 - 8
test/unit/reports/test_rpt_test_template.js

@@ -30,7 +30,7 @@ let demoPrjId = - 1;
 // let demoRptId = 6; //封面
 // let demoRptId = 22; //03
 // let demoRptId = 26; //07
-let demoRptId = 28; //09
+// let demoRptId = 28; //09
 // let demoRptId = 27; //08
 // let demoRptId = 24; //05
 // let demoRptId = 20; //01
@@ -47,6 +47,7 @@ let demoRptId = 28; //09
 // let demoRptId = 68; //01-2
 // let demoRptId = 71; //21-2
 // let demoRptId = 74; //22
+let demoRptId = 81; //02
 
 let pagesize = "A4";
 //288: 11-2表(新)
@@ -63,13 +64,16 @@ let userId_Leng = "5c3ffa9aa0a92732f41216e0"; //小冷User Id (养护的)
 // demoPrjId = 455; //PROD:
 // demoPrjId = 776; //PROD:
 // demoPrjId = 671; //PROD:
-demoPrjId = 2056; //UAT
-// demoPrjId = 1516; //PROD:
-// demoPrjId = 756; //PROD:
+// demoPrjId = 2056; //UAT
+// demoPrjId = 815; //UAT
+// demoPrjId = 1510; //PROD:
+// demoPrjId = 618; //PROD:
+// demoPrjId = 2580; //PROD:
 // demoPrjId = 815; //PROD:
-// demoPrjId = 4107; //UAT:
+demoPrjId = 499; //UAT:
 //*/
 let userId_Dft = userId_Leng;
+// userId_Dft = '5c641205950967000d20d35b'; //临时用
 // let userId_Dft = "5a025c4c15074d134c2b9689";
 /*/
  let userId_Dft = "595328da1934dc327cad08eb";
@@ -107,10 +111,10 @@ test('测试 - 测试模板啦: ', function (t) {
                 try {
                     let dt = new Date();
                     console.log('取完项目数据时间:' + (dt));
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/YangHuCost/tmp/rptTplRawDataObject_测试模板.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/YangHuCost/tmp/rptTplRawDataObject_测试模板.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
                     // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/YangHuCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
-                    fsUtil.writeObjToFile(tplData, "D:/GitHome/YangHuCost/tmp/rptTplAssembledData_测试模板.jsp");
+                    // fsUtil.writeObjToFile(tplData, "D:/GitHome/YangHuCost/tmp/rptTplAssembledData_测试模板.jsp");
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();
                     rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
@@ -128,7 +132,7 @@ test('测试 - 测试模板啦: ', function (t) {
                     }
                     if (pageRst) {
                         // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板" + dt.getTime() + ".jsp");
-                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板.jsp");
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板.jsp");
                         // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
                         //     console.log("excel uuid: " + uuidName);
                         // });

二進制
web/building_saas/img/FirstPageSimple.cur


二進制
web/building_saas/img/LastPageSimple.cur


二進制
web/building_saas/img/NextPageSimple.cur


二進制
web/building_saas/img/PreviousPageSimple.cur


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

@@ -1687,7 +1687,7 @@ class CalcProgram {
                     btf = sum_rtf;
                     bttf = sum_rttf;
 
-                    if (calcTools.isBillProject()) {  // 招投标项目, 还要反算
+                    if (calcTools.isBillProject() && (ft.type == 'common' || ft.type == 'rationCommon')) {  // 招投标项目, 还要反算
                         buf = buf.toDecimal(decimalObj.bills.unitPrice);
                         btuf = btuf.toDecimal(decimalObj.bills.unitPrice);
                         btf = (buf * nQ).toDecimal(decimalObj.bills.totalPrice);

+ 3 - 1
web/building_saas/main/js/models/project_glj.js

@@ -310,10 +310,11 @@ ProjectGLJ.prototype.updateCalcMaterial =async function (projectGLJ,updateField,
                     glj.unit_price[key] = ext[key];
                 }
             }
-            if(updateField == 'calcMaterial' && value ==0){///标记为0即删除材料计算标记,要删除其下挂的原价计算,运费计算,定额计算
+            if(updateField == 'calcMaterial' && value ==0){///标记为0即删除材料计算标记,要删除其下挂的原价计算,运费计算,定额计算,消耗量重新计算
                 let connect_key = gljUtil.getIndex(glj);
                 _.remove(this.datas.originalList,{'connect_key':connect_key});
                 _.remove(this.datas.freightList,{'connect_key':connect_key});
+                this.calcQuantity();
                 // to do 删除定额计算
 
             }
@@ -472,6 +473,7 @@ ProjectGLJ.prototype.m_updateUnitPrice = function (datas) {//批量更新
         let g = updateUnit(d.id,d.unitPrice);
         if(g) gljList.push(g);
     }
+    this.calcQuantity();
     //刷新项目工料机表显示
     projectGljObject.refreshDataSheet();
     //重新计算相关节点

+ 3 - 0
web/building_saas/main/js/models/ration.js

@@ -392,6 +392,9 @@ var Ration = {
             if(libIDs == null){
                 return;
             }
+            //设置定额库的优先级,默认先取选中的定额库,如果没有再取default定额库
+            let selectedLib = sessionStorage.getItem("stdRationLib");
+            selectedLib&&selectedLib!='undefined'?libIDs.unshift(selectedLib):libIDs.unshift(defaultLibID);
             for(let r of recodes){
                 let needInstall = false;
                 if(projectObj.project.isInstall()) {//如果是安装工程,要看需不需要生成安装增加费

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

@@ -620,7 +620,7 @@ var projectObj = {
                 libID = rationLibObj.compleRationLibId;
             }
             if(!rationLibObj.tree){
-                sessionStorage.setItem('stdRationLib', libID);
+                if(isDef(libID)) sessionStorage.setItem('stdRationLib', libID);
                 rationLibObj.doAfterGetRationTree = function () {
                     this.locateAtRation(libID, code);
                     this.doAfterGetRationTree = null;

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

@@ -343,6 +343,7 @@ var rationLibObj = {
         me.loadSectionRations(sectionNode && sectionNode.children.length === 0 ? sectionNode.data.ID : null);
     },
     locateAtRation: function(libID, code){
+        if(!isDef(libID)) return;
         let me = rationLibObj;
         if ($('#rationSearchResult').is(':visible')) {
             $('#rationSearchResult a').click();

+ 14 - 5
web/building_saas/report/js/jpc_output.js

@@ -147,10 +147,13 @@ let JpcCanvasOutput = {
                 validTxtLines = Math.floor((area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] + 4));
             }
 
-            function private_drawUnderline() {
+            function private_drawUnderline(underLineVal) {
                 //A. 暂不支持角度; B. 坐标已经translate
                 //1. 计算下划线的相关坐标
-                let width = ctx.measureText(val).width;
+                let width = ctx.measureText(underLineVal).width;
+                if (width > area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) {
+                    width = area[JV.IDX_RIGHT] - area[JV.IDX_LEFT];
+                }
                 let height = dftFontHeight;
                 // let startX = area[JV.IDX_LEFT], startY = area[JV.IDX_TOP], endX = area[JV.IDX_RIGHT], endY = area[JV.IDX_BOTTOM];
                 let startX = 0, startY = 0, endX = width, endY = startY;
@@ -189,9 +192,9 @@ let JpcCanvasOutput = {
 
             ctx.save();
             ctx.translate(output[0], output[1]);
-            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
-                private_drawUnderline();
-            }
+            // if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+            //     private_drawUnderline(val);
+            // }
             if (font.FontAngle === JV.VERTICAL_ANGLE) {
                 ctx.rotate(Math.PI/2);
             } else if (font.FontAngle === JV.ANTI_VERTICAL_ANGLE) {
@@ -199,6 +202,9 @@ let JpcCanvasOutput = {
             }
             if (validAreaTxtWidth >= ctx.measureText(val).width ||
                 (control && control.Shrink !== 'T' && validTxtLines < private_splitString(val, validAreaTxtWidth, ctx)) ) {
+                if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                    private_drawUnderline(val);
+                }
                 ctx.fillText(val, 0, 0);
             } else {
                 while (true) {
@@ -228,6 +234,9 @@ let JpcCanvasOutput = {
                             ctx.translate(-output[0], -output[1]);
                             inner_setupControl(newArea, dftFontHeight, output);
                             ctx.translate(output[0], output[1]);
+                            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                                private_drawUnderline(actLines[lIdx]);
+                            }
                             ctx.fillText(actLines[lIdx], 0, 0);
                         }
                         break;

+ 2 - 1
web/building_saas/report/js/rpt_print.js

@@ -244,7 +244,8 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
                 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] - JV.OUTPUT_OFFSET[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]), ctx);
-        if (actLines.length === 1 || (control && control.Shrink !== 'T')) {
+        let validTxtLines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
+        if (actLines.length === 1  || (control && control.Shrink !== 'T' && validTxtLines < actLines)) {
             inner_build_text(textValue, area);
         } else {
             while (true) {