Sfoglia il codice sorgente

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

chenshilong 6 anni fa
parent
commit
38544ed22e
35 ha cambiato i file con 506 aggiunte e 220 eliminazioni
  1. 1 1
      config/config.js
  2. 1 0
      config/gulpConfig.js
  3. 7 0
      modules/all_models/compleRation_ration.js
  4. 1 0
      modules/all_models/ration.js
  5. 26 0
      modules/all_models/ration_template.js
  6. 9 2
      modules/all_models/stdRation_ration.js
  7. 2 6
      modules/main/controllers/bills_controller.js
  8. 4 1
      modules/main/facade/bill_facade.js
  9. 47 5
      modules/main/facade/ration_facade.js
  10. 21 0
      modules/main/facade/ration_template_facade.js
  11. 2 1
      modules/main/models/project.js
  12. 1 0
      modules/main/models/project_consts.js
  13. 1 1
      modules/pm/facade/pm_facade.js
  14. 4 2
      modules/ration_glj/facade/ration_glj_facade.js
  15. 16 0
      modules/reports/rpt_component/helper/jpc_helper_field.js
  16. 13 0
      modules/reports/rpt_component/jpc_flow_tab.js
  17. 1 1
      modules/reports/util/rpt_pdf_util.js
  18. 20 2
      public/web/sheet/sheet_common.js
  19. 12 9
      test/unit/reports/test_rpt_test_template.js
  20. 11 6
      test/unit/reports/test_tpl_05.js
  21. 4 3
      web/building_saas/main/html/main.html
  22. 19 4
      web/building_saas/main/js/controllers/block_controller.js
  23. 1 7
      web/building_saas/main/js/models/bills.js
  24. 1 0
      web/building_saas/main/js/models/main_consts.js
  25. 1 0
      web/building_saas/main/js/models/project.js
  26. 16 15
      web/building_saas/main/js/models/ration.js
  27. 38 0
      web/building_saas/main/js/models/ration_template.js
  28. 3 2
      web/building_saas/main/js/views/importBills.js
  29. 12 2
      web/building_saas/main/js/views/installation_fee_view.js
  30. 92 12
      web/building_saas/main/js/views/mbzm_view.js
  31. 1 0
      web/building_saas/main/js/views/project_view.js
  32. 2 8
      web/building_saas/main/js/views/sub_view.js
  33. 56 5
      web/building_saas/pm/html/project-management.html
  34. 59 124
      web/building_saas/pm/js/pm_newMain.js
  35. 1 1
      web/building_saas/report/js/rpt_main.js

+ 1 - 1
config/config.js

@@ -28,7 +28,7 @@ module.exports = {
                 useMongoClient: true
             }
     },
-    pp:{  server: "172.18.111.231",
+    pp:{  server: "112.74.42.187",
         port: "27017",
         options:{
             user:'smartcost',

+ 1 - 0
config/gulpConfig.js

@@ -97,6 +97,7 @@ module.exports = {
         'web/building_saas/main/js/models/ration_coe.js',
         'web/building_saas/main/js/models/ration_ass.js',
         'web/building_saas/main/js/models/ration_installation.js',
+        'web/building_saas/main/js/models/ration_template.js',
         // 'web/building_saas/main/js/models/volume_price.js',
         'web/building_saas/main/js/models/labour_coe.js',
         'web/building_saas/main/js/models/installation_fee.js',

+ 7 - 0
modules/all_models/compleRation_ration.js

@@ -55,6 +55,13 @@ const compleRationSchema = new Schema({
     rationCoeList: Array,
     rationAssList: [compleRationAssItemSchema],
     rationInstList: [rationInstSchema],
+    rationTemplateList : [new Schema({
+        type: String,
+        code: String,
+        name: String,
+        billsLocation: String,
+        unit:String
+    }, { _id: false })],
     deleteInfo: deleteSchema
 }, {versionKey: false});
 

+ 1 - 0
modules/all_models/ration.js

@@ -67,6 +67,7 @@ let rationSchema = new Schema({
     annotation: String,                         //附注
     ruleText: String,                            // 计算规则
     prefix: {type: String, default: ''},                              //定额是补充、借用时用  补 借
+    referenceRationID:String,//如果是通过模板关联子目生成的定额,这里记录对应的主定额ID
 
     //工料机特有属性
     projectGLJID:Number,  //项目工料机ID

+ 26 - 0
modules/all_models/ration_template.js

@@ -0,0 +1,26 @@
+/**
+ * Created by zhang on 2018/11/26.
+ */
+
+var mongoose = require('mongoose'),
+    Schema = mongoose.Schema;
+
+let ration_template =  new Schema({
+    ID:String,
+    projectID: Number,
+    rationID:String,
+    createLocation:Number,//提取位置
+    templateList:[new Schema({
+        code:String,
+        name:String,
+        type:String,
+        billsLocation:String,//这个是清单编号
+        fxID:String,//这个是分项对应的ID
+        unit:String,
+        quantity:String,
+        coe:String,
+        billID:String//记取位置对应的清单ID
+    },{ _id: false })]
+},{versionKey:false});
+
+mongoose.model('ration_template', ration_template);

+ 9 - 2
modules/all_models/stdRation_ration.js

@@ -46,7 +46,14 @@ const rationItemSchema = new Schema({
     rationGljList: [rationGljItemSchema],
     rationCoeList: Array,
     rationAssList: [rationAssItemSchema],
-    rationInstList: [rationInstSchema]
-});
+    rationInstList: [rationInstSchema],
+    rationTemplateList : [new Schema({
+        type: String,
+        code: String,
+        name: String,
+        billsLocation: String,
+        unit:String
+    }, { _id: false })]
 
+});
 mongoose.model('std_ration_lib_ration_items', rationItemSchema, 'std_ration_lib_ration_items');

+ 2 - 6
modules/main/controllers/bills_controller.js

@@ -8,9 +8,7 @@ let ProjectsData = require('../../pm/models/project_model').project;
 let logger = require("../../../logs/log_helper").logger;
 let quantity_detail = require("../facade/quantity_detail_facade");
 let bill_facade = require("../facade/bill_facade");
-let ration_glj = mongoose.model('ration_glj');
-let ration_coe = mongoose.model('ration_coe');
-let rationInstallationModel = mongoose.model('ration_installation');
+let raiton_facade = require("../facade/ration_facade");
 let stdBillsModel = mongoose.model('std_bills_lib_bills');
 let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');
 let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');
@@ -425,9 +423,7 @@ async function doBillsOrRationsDelete(data) {
         await quantity_detail.deleteByQuery(qd_query) ;
     }
     if(sub_query!=null){
-        await ration_coe.deleteMany(sub_query);//删除附注条件
-        await ration_glj.deleteMany(sub_query);//删除定额工料机
-        await rationInstallationModel.deleteMany(sub_query);//删除安装增加费
+        await raiton_facade.deleteSubListByQuery(sub_query);
     }
     if(rationTask.length>0){
         await ration_model.model.bulkWrite(rationTask);//删除定额

+ 4 - 1
modules/main/facade/bill_facade.js

@@ -14,6 +14,7 @@ let ration_Model = mongoose.model('ration');
 let ration_glj_Model = mongoose.model('ration_glj');
 let ration_coe_Model = mongoose.model('ration_coe');
 let ration_installation_Model = mongoose.model('ration_installation');
+let ration_template_Model = mongoose.model('ration_template');
 let bill_Model = require('../models/bills').model;
 import GLJController from "../../glj/controllers/glj_controller";
 
@@ -89,6 +90,7 @@ async function pasteOtherData(data) {
     let quantity_details = data.quantity_details;
     let ration_coes = data.ration_coes;
     let ration_installations = data.ration_installations;
+    let ration_templates = data.ration_templates;
     let updateData = data.updateData;
     let uModel = null;
     let tasks = [];
@@ -113,9 +115,10 @@ async function pasteOtherData(data) {
     quantity_details.length > 0 ? await insertMany(quantity_details,quantity_detail_model):'';
     ration_coes.length > 0 ? await insertMany(ration_coes,ration_coe_Model):'';
     ration_installations.length > 0 ? await insertMany(ration_installations,ration_installation_Model):'';
+    ration_templates.length > 0? await insertMany(ration_templates,ration_template_Model):'';
     tasks.length>0?await uModel.bulkWrite(tasks):'';
 
-    return {bills:bills,quantity_details:quantity_details,ration_coes:ration_coes,ration_installations:ration_installations,updateData:updateData}
+    return {bills:bills,quantity_details:quantity_details,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_templates,updateData:updateData}
 }
 
 async function pasteRationsAndRationGLJ (rations,ration_gljs) {

+ 47 - 5
modules/main/facade/ration_facade.js

@@ -13,6 +13,7 @@ let bill_model = require('../models/bills');
 let decimal_facade = require('./decimal_facade');
 let installationFeeModel = mongoose.model("installation_fee");
 let rationInstallationModel = mongoose.model('ration_installation');
+let rationTemplateModel = mongoose.model('ration_template');
 const uuidV1 = require('uuid/v1');
 let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
 let complementary_glj_model =  mongoose.model('complementary_glj_lib');
@@ -32,7 +33,8 @@ module.exports = {
     addMultiRation: addMultiRation,
     getSameSectionRations:getSameSectionRations,
     getExtendData:getExtendData,
-    getDefaultProgramID:getDefaultProgramID
+    getDefaultProgramID:getDefaultProgramID,
+    deleteSubListByQuery:deleteSubListByQuery
 };
 async function addNewRation(data,compilation) {
     let query = data.itemQuery;
@@ -202,13 +204,15 @@ async function addRationSubList(stdRation,newRation,needInstall,compilation) {
     let ration_coes = await addRationCoe(stdRation,newRation,compilation);
     let addRationCoeTime = +new Date();
     console.log("添加定额coe时间-----"+(addRationCoeTime - addRationGLJTime));
-    let ration_installs = [];
+    let ration_installations = [];
     if(needInstall && stdRation.type == 'std'){//只有标准的定额才有安装增加费,补充的定额没有安装增加费
-        ration_installs =  await addRationInstallFee(stdRation,newRation);
+        ration_installations =  await addRationInstallFee(stdRation,newRation);
     }
     let addRationInstallFeeTime = +new Date();
     console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
-    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installs:ration_installs};
+    //添加定额模板子目
+    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]};
 }
 
 async function addRationInstallFee(std,newRation) {
@@ -250,6 +254,38 @@ async function addRationInstallFee(std,newRation) {
     return install_fee_list;
 }
 
+async function addRationTemplate(std,newRation) {
+    let templateList = [];
+    if(std.hasOwnProperty('rationTemplateList') && std.rationTemplateList.length > 0){
+        for(let tem of std.rationTemplateList){
+            let template = {
+                billID:"",
+                fxID:"",
+                quantity:"0",
+                coe:"0"
+            }
+            template.code = tem.code;
+            template.name = tem.name;
+            template.type = tem.type;
+            template.unit = tem.unit &&_.isString(tem.unit)?tem.unit.replace(/^\d+/,""):"";
+            template.billsLocation = template.billsLocation
+            templateList.push(template)
+        }
+    }
+    if(templateList.length > 0){
+        let ration_template = {};
+        ration_template.ID = uuidV1();
+        ration_template.projectID = newRation.projectID;
+        ration_template.rationID = newRation.ID;
+        ration_template.createLocation = 1; //默认模板子目分别放在措施项目下
+        ration_template.templateList = templateList;
+        await  rationTemplateModel.create(ration_template);
+        return ration_template;
+    }
+    return null;
+}
+
+
 async function addRationCoe(std,newRation,compilation) {
     let ration_coe_list = [];
     let seq = 0;
@@ -424,12 +460,18 @@ async function addRationGLJ(std,newRation,compilation) {
 async function deleRationSubRecode(projectID,rationID) {//删除挂在定额下的数据,如工程量明细,定额工料机等
     let delete_query={projectID: projectID, rationID: rationID};
     //删除工程量明细
-    await quantity_detail.deleteByQuery(delete_query) ;
+    await deleteSubListByQuery(delete_query) ;
+}
+
+async function deleteSubListByQuery(delete_query) {
+    await quantity_detail.deleteByQuery(delete_query) ;//删除工程量明细
     await ration_coe.deleteMany(delete_query);//删除附注条件
     await ration_glj.deleteMany(delete_query);//删除定额工料机
     await rationInstallationModel.deleteMany(delete_query);//删除安装增加费
+    await rationTemplateModel.deleteMany(delete_query);//删除模板关联子目
 }
 
+
 async function  updateRation(std,defaultLibID,rationID,billsItemID,projectID,calQuantity) {
     // insertNewRation
     let ration ={};

+ 21 - 0
modules/main/facade/ration_template_facade.js

@@ -0,0 +1,21 @@
+/**
+ * Created by zhang on 2018/11/26.
+ */
+
+let mongoose = require('mongoose');
+let rationTemplateModel = mongoose.model('ration_template');
+let consts = require('../models/project_consts');
+
+module.exports={
+    getData:getData,
+};
+
+function getData(projectID, callback) {
+    rationTemplateModel.find({'projectID': projectID}, (err, datas) => {
+        if (err) {
+            callback(1, '', null);
+        } else {
+            callback(0, consts.projectConst.RATION_TEMPLATE, datas);
+        }
+    })
+}

+ 2 - 1
modules/main/models/project.js

@@ -7,6 +7,7 @@ var ration_glj_data = require('../../ration_glj/facade/ration_glj_facade');
 var ration_coe_data = require('../../ration_glj/facade/ration_coe_facade');
 var ration_ass_data = require('../../ration_glj/facade/ration_ass_facade');
 let ration_installation = require('../facade/ration_installation_facade');
+let ration_template = require('../facade/ration_template_facade');
 var quantity_detail_data = require('../facade/quantity_detail_facade');
 var fee_rate_data = require('../../fee_rates/facade/fee_rates_facade');
 let projCounter = require('./proj_counter_model');
@@ -41,7 +42,7 @@ moduleMap[projectConsts.LABOUR_COE] = labour_coe_facade;
 moduleMap[projectConsts.CALC_PROGRAM] = calc_program_facade;
 moduleMap[projectConsts.PROJECTGLJ] = new GLJController();
 moduleMap[projectConsts.INSTALLATION_FEE] = installation_facade;
-
+moduleMap[projectConsts.RATION_TEMPLATE] = ration_template;
 
 var Project = function (){};
 

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

@@ -10,6 +10,7 @@ let projectConst = {
     RATION_COE:'ration_coe',
     RATION_ASS:'ration_ass',
     RATION_INSTALLATION:'ration_installation',
+    RATION_TEMPLATE:'ration_template',
     QUANTITY_DETAIL:'quantity_detail',
     PROJECTGLJ: 'projectGLJ',
     GLJLIST: 'GLJList',

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

@@ -631,7 +631,7 @@ async function getSummaryInfoByTender(tenderID, summaryType) {
             if(summaryInfo[t.ID]){
                 summaryInfo[t.ID]['name'] = t.name ? t.name : '';
                 summaryList.push(summaryInfo[t.ID]);
-            }k
+            }
         }
     }
     else {

+ 4 - 2
modules/ration_glj/facade/ration_glj_facade.js

@@ -316,13 +316,15 @@ async function doCustomQuantityUpdate(datas) {
 
 function delete_ration_glj(user_id, datas) {
     return function (callback) {
-        if (datas.deleteType == "RATION") {
+        callback(new Error("删除子数据失败!"),null)
+        //这个方法已经不用,先注释,稳定后再删除
+       /* if (datas.deleteType == "RATION") {
             deleteByRation(datas, callback);
         } else if (datas.deleteType == "BILL") {
             deleteByBill(user_id, datas, callback);
         } else {
             deleteByID(datas, callback);
-        }
+        }*/
     }
 }
 

+ 16 - 0
modules/reports/rpt_component/helper/jpc_helper_field.js

@@ -123,6 +123,22 @@ let JpcFieldHelper = {
                     }
                 }
             }
+            if (!isEx) {
+                let dis_detail_fields = rptTpl[JV.NODE_NO_MAPPING_FIELDS];
+                for (let i = 0; i < tab_fields.length; i++) {
+                    if (tab_fields[i][JV.PROP_IS_AUTO_HEIGHT]) {
+                        for (let j = 0; j < dis_detail_fields.length; j++) {
+                            if (tab_fields[i]["FieldID"] === dis_detail_fields[j]["ID"]) {
+                                let item = [];
+                                item[0] = JV.BLANK_FIELD_INDEX;
+                                item[1] = tab_fields[i];
+                                rstFieldsIdx.push(item);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
         }
     }
 };

+ 13 - 0
modules/reports/rpt_component/jpc_flow_tab.js

@@ -357,11 +357,24 @@ JpcFlowTabSrv.prototype.createNew = function(){
             let private_get_max_lines_of_the_record = function(theRecIdx) {
                 let rst = 1;
                 for (let loop = 0; loop < me.auto_height_fields_idx.length; loop++) {
+                    /*
                     let data_field = null;
                     let tab_field = me.auto_height_fields_idx[loop][1];
                     if (me.auto_height_fields_idx[loop][0] !== JV.BLANK_FIELD_INDEX) {
                         data_field = data_details[me.auto_height_fields_idx[loop][0]];
                     }
+                    /*/
+                    let tab_field = me.auto_height_fields_idx[loop][1];
+                    let data_field = null,
+                        map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
+                    if (me.auto_height_fields_idx[loop][0] !== JV.BLANK_FIELD_INDEX && (typeof me.auto_height_fields_idx[loop][0] !== 'object')) {
+                        data_field = data_details[me.auto_height_fields_idx[loop][0]];
+                    } else {
+                        if (map_data_field) {
+                            data_field = map_data_field[JV.PROP_AD_HOC_DATA];
+                        }
+                    }
+                    //*/
                     if (data_field) {
                         let value = JpcFieldHelper.getValue(data_field, theRecIdx);
                         let area = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, 1, 1, 0, 1, 0, 1, 0, false, false);

+ 1 - 1
modules/reports/util/rpt_pdf_util.js

@@ -234,7 +234,7 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
                     doc.fontSize(dftFontHeight);
                     options.width = w;
                     options.height = dftFontHeight;
-                    doc.text(val,output[0], output[1], options);
+                    // 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;
                     if ((aH * actLines.length) < (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) && (control && control.Vertical !== 'top')) {

+ 20 - 2
public/web/sheet/sheet_common.js

@@ -264,9 +264,9 @@ var sheetCommonObj = {
             for (var i = 0; i < setting.view.lockColumns.length; i++) {
                 let col = setting.view.lockColumns[i];
                 if(_.isString(col)){//如果是dataCode 进行转换
-                    col = _.findIndex(setting.header,{dataCode:tem})
+                    col = _.findIndex(setting.header,{dataCode:col})
                 }
-                sheet.getRange(-1,setting.view.lockColumns[i], -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                sheet.getRange(-1,col, -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
             }
         }
     },
@@ -889,5 +889,23 @@ var sheetCommonObj = {
         ctx.stroke();
         ctx.restore();
         return offset;
+    },
+    checkData:function(col,setting, value) {
+        let result = true;
+        let validator = setting.header[col].validator !== undefined ? setting.header[col].validator : null;
+        if (validator === null) {
+            return result;
+        }
+        switch (validator) {
+            case 'number':
+                let regular = /^\d+(\.\d+)?$/;
+                result = regular.test(value);
+                break;
+            case 'boolean':
+                let booleanValue = [true, false];
+                result = booleanValue.indexOf(value) >= 0;
+                break;
+        }
+        return result;
     }
 }

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

@@ -37,13 +37,15 @@ let demoPrjId = - 1;
 // let demoRptId = 626; //06
 // let demoRptId = 451; //09-1
 // let demoRptId = 452; //04
-let demoRptId = 612; //09-3
+// let demoRptId = 612; //09-3
 // let demoRptId = 530; //封2
 // let demoRptId = 386; //04
 // let demoRptId = 389; //10
 // let demoRptId = 280; //11-1 暂列金
+let demoRptId = 514; //12
 // let demoRptId = 2260; //测试基本信息
 // let demoRptId = 613; //09-4 2018
+// let demoRptId = 726; //定制:清单子目表
 let pagesize = "A4";
 //288: 11-2表(新)
 //279: 04
@@ -55,7 +57,8 @@ let userId_HaiZhu = "5b5a66c4a3c23e000dccdd77"; //海珠user id
 // demoPrjId = 720; //QA: DW3
 //demoPrjId = 1626; //QA:
 // demoPrjId = 2260; //QA:
-demoPrjId = 4563; //QA:
+demoPrjId = 4529; //QA:
+// demoPrjId = 4107; //UAT:
 //*/
 let userId_Dft = userId_HaiZhu;
 // let userId_Dft = "5a025c4c15074d134c2b9689";
@@ -86,10 +89,10 @@ test('测试 - 测试模板啦: ', function (t) {
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_测试模板.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_测试模板.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
-                    fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptTplAssembledData_测试模板.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
+                    // fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/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;
@@ -101,13 +104,13 @@ test('测试 - 测试模板啦: ', function (t) {
                     let customizeCfg = {"fillZero": true};
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
                     if (pageRst) {
-                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult_测试模板.jsp");
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult_测试模板.jsp");
                         // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
                         //     console.log("excel uuid: " + uuidName);
                         // });
-                        // rpt_pdf_util.export_pdf_file(pageRst, pagesize, 'local_test_rpt_pdf', function(uuidName){
-                        //     console.log("pdf uuid: " + uuidName);
-                        // });
+                        rpt_pdf_util.export_pdf_file(pageRst, pagesize, 'local_test_rpt_pdf', function(uuidName){
+                            console.log("pdf uuid: " + uuidName);
+                        });
                     } else {
                         console.log("oh! no pages were created!");
                     }

+ 11 - 6
test/unit/reports/test_tpl_05.js

@@ -31,7 +31,8 @@ let demoRptId = 626; //06
 let pagesize = "A4";
 
 // demoPrjId = 720; //QA: DW3
-demoPrjId = 4563; //QA:
+// demoPrjId = 4563; //QA:
+demoPrjId = 4107; //UAT:
 //*/
 // let userId_Leng = "59cdf14a0034a1000ba52b97"; //小冷User Id 换成_id了
 let userId_Leng = "5b5a66c4a3c23e000dccdd77"; //海珠的 _id
@@ -89,11 +90,15 @@ test('测试 - 模板05汇总表: ', function (t) {
                         }
                     });
                 } else  if (promiseArr[1] !== null) {
-                    promiseArr[1].then(function (rst) {
-                        rawDataObj.Segment = rst.parent;
-                        rawDataObj.SegmentDetail = rst.subList;
-                        buildPageData(t, rawDataObj, rptDataUtil, rptTpl);
-                    });
+                    try {
+                        promiseArr[1].then(function (rst) {
+                            rawDataObj.Segment = rst.parent;
+                            rawDataObj.SegmentDetail = rst.subList;
+                            buildPageData(t, rawDataObj, rptDataUtil, rptTpl);
+                        });
+                    } catch (ex) {
+                        console.log(ex);
+                    }
                 } else {
                     buildPageData(t, rawDataObj, rptDataUtil, rptTpl);
                 }

+ 4 - 3
web/building_saas/main/html/main.html

@@ -88,7 +88,7 @@
                     <span class="btn btn-light btn-sm" id="importSpan" data-toggle="tooltip" data-original-title="导入" data-placement="bottom">
                         <a class="dropdown-toggle" href="#" data-toggle="dropdown"><i class="fa fa-cloud-upload"></i></a>
                         <div class="dropdown-menu">
-                            <a id="uploadLj" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入09表Excel清单</a>
+                            <a id="uploadLj" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入表Excel清单</a>
                             <a id="uploadGld" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入广联达算量Excel清单</a>
                         </div>
                     </span>
@@ -177,7 +177,7 @@
                   <div class="row">
                       <!--col-lg-12 p-0-->
                       <div class="main-content" style="width: 100%; display: inline-block" id="main">
-                          <div class="top-content" id="top_div">
+                          <div class="top-content" id="top_div" style="overflow:hidden;">
                               <div class="main-data-top" id="billsSpread"></div>
                           </div>
                           <div class="resize"></div>
@@ -242,7 +242,7 @@
                                                   <div class="row" style="border-bottom:1px solid #ccc">
                                                       <label class="col-auto col-form-label col-form-label-sm">提取位置</label>
                                                       <div class="col-2">
-                                                          <select class="form-control  form-control-sm" id="">
+                                                          <select class="form-control  form-control-sm" id="createLocation">
                                                               <option value="1">模板子目分别放在措施项目下</option>
                                                               <option value="2">模板子目分别放在分部分项下</option>
                                                               <option value="3">模板子目分别放在对应混凝土子目下</option>
@@ -1850,6 +1850,7 @@
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration_coe.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration_ass.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration_installation.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/models/ration_template.js"></script>
     <!--<script type="text/javascript" src="/web/building_saas/main/js/models/volume_price.js"></script>-->
     <script type="text/javascript" src="/web/building_saas/main/js/models/labour_coe.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/calc_program.js"></script>

+ 19 - 4
web/building_saas/main/js/controllers/block_controller.js

@@ -127,6 +127,7 @@ let BlockController = {
             data.ration_coes = projectObj.project.ration_coe.getCoeByRationID(data.ID);
             data.ration_installations =  projectObj.project.ration_installation.getInstallationByRationID(data.ID);
             data.quantity_details = projectObj.project.quantity_detail.getDetailByRationID(data.ID);
+            data.ration_template = projectObj.project.ration_template.getTemplateByRationID(data.ID);
         }else if(node.children.length>0){
             let children = [];
             for(let c of node.children){
@@ -290,10 +291,11 @@ let BlockController = {
         let mainTree = project.mainTree;
         Bills.addDatasToList(result.bills);
         Ration.addDatasToList(result.rations);
-        project.quantity_detail.addDatasToList(result.quantity_details);
+        Ration.addSubListOfRation(result);//这里是新插入定额时
+      /*  project.quantity_detail.addDatasToList(result.quantity_details);
         project.ration_glj.addDatasToList(result.ration_gljs);
         project.ration_coe.addDatasToList(result.ration_coes);
-        project.ration_installation.addDatasToList(result.ration_installations);
+        project.ration_installation.addDatasToList(result.ration_installations);*/
         for(let u of  result.updateData){
             let unode = mainTree.findNode(u.query.ID);
             if(unode){
@@ -390,7 +392,7 @@ let BlockController = {
     preparePasteData : function (datas,billsIDMap,firstParentID,lastNextID) {
         let me = this;
         me.datas = _.cloneDeep(projectObj.project.Bills.datas);
-        let bills = [],rations=[],ration_gljs = [],ration_coes = [],quantity_details = [],ration_installations = [];
+        let bills = [],rations=[],ration_gljs = [],ration_coes = [],quantity_details = [],ration_installations = [],ration_templates=[];
         let firstBillIDs = [],lastBillID = null;//记录第一层清单的ID,和第一层的最后一个清单ID
         let firstIDMap = {};
         for(let i = 0 ;i< datas.length ;i++){
@@ -420,7 +422,7 @@ let BlockController = {
         }
 
 
-        return {bills:bills,rations:rations,ration_gljs:ration_gljs,ration_coes:ration_coes,quantity_details:quantity_details,ration_installations:ration_installations};
+        return {bills:bills,rations:rations,ration_gljs:ration_gljs,ration_coes:ration_coes,quantity_details:quantity_details,ration_installations:ration_installations,ration_templates:ration_templates};
 
         function eachData(data) {
             if(data.sourceType == 'bills'){
@@ -453,10 +455,22 @@ let BlockController = {
                 for(let ri of data.ration_installations){
                     ration_installations.push(createSubList(ri,tem_r));
                 }
+                if(data.ration_template){
+                    ration_templates.push(createRationTemplate(data.ration_template,tem_r))
+                }
             }
 
         }
 
+        function createRationTemplate(oldTem,rationData) {
+            let template = _.cloneDeep(oldTem);
+            delete template._id;
+            template.ID = uuid.v1();
+            template.projectID = projectObj.project.ID();
+            template.rationID = rationData.ID;
+            return template;
+        }
+        
         function createSubList(subData,rationData) {
             let tem_sub = _.cloneDeep(subData);
             delete tem_sub._id;
@@ -490,6 +504,7 @@ let BlockController = {
             delete tem_ration.ration_coes;
             delete tem_ration.ration_installations;
             delete tem_ration.quantity_details;
+            delete tem_ration.referenceRationID;//删除关联的主定额信息
             delete tem_ration.__v;
             delete tem_ration.sourceType;
 

+ 1 - 7
web/building_saas/main/js/models/bills.js

@@ -756,9 +756,6 @@ var Bills = {
             CommonAjax.post("/bills/multiDelete", updateData, function () {
                 let quantity_detail_datas = project.quantity_detail.datas;
                 let ration_datas = project.Ration.datas;
-                let ration_glj_datas = project.ration_glj.datas;
-                let ration_coe_datas = project.ration_coe.datas;
-                let ration_install_datas = project.ration_installation.datas;
                 let nodes = controller.tree.nodes;
                 let prefix = controller.tree.prefix;
                 //更新缓存
@@ -777,10 +774,7 @@ var Bills = {
                 if(updateData['ration']){
                     for(let r_key in updateData['ration']){//定额只有删除,没有更新
                         _.remove(ration_datas,{'ID':r_key});
-                        _.remove(quantity_detail_datas,{'rationID':r_key});
-                        _.remove(ration_glj_datas,{'rationID':r_key});
-                        _.remove(ration_coe_datas,{'rationID':r_key});
-                        _.remove(ration_install_datas,{'rationID':r_key});
+                        project.Ration.deleteSubListOfRation({ID:r_key});
                     }
                 }
                 controller.m_delete(mainNodes);//删除树节点

+ 1 - 0
web/building_saas/main/js/models/main_consts.js

@@ -12,6 +12,7 @@ const ModuleNames = {
     ration_coe:'ration_coe',
     ration_ass:'ration_ass',
     ration_installation:'ration_installation',
+    ration_template:'ration_template',
     quantity_detail:'quantity_detail',
     labour_coe: 'labour_coe',
     calc_program: 'calc_program',

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

@@ -80,6 +80,7 @@ var PROJECT = {
             this.ration_coe = ration_coe.createNew(this);
             this.ration_ass = ration_ass.createNew(this);
             this.ration_installation = ration_installation.createNew(this);
+            this.ration_template = ration_template.createNew(this);
             this.quantity_detail = quantity_detail.createNew(this);
             this.installation_fee = installation_fee.createNew(this);
             this.FeeRate = FeeRate.createNew(this);

+ 16 - 15
web/building_saas/main/js/models/ration.js

@@ -269,11 +269,7 @@ var Ration = {
         ration.prototype.delete = function (ration) {
             var ration_glj =projectObj.project.ration_glj;
             this.project.pushNow('deleteRation', [this.getSourceType(),ration_glj.getSourceType()], [this.getDeleteData(ration),ration_glj.getDeleteDataByRation(ration)]);
-
-            project.ration_glj.deleteByRation(ration);
-            project.ration_coe.deleteByRation(ration);
-            project.quantity_detail.deleteByRation(ration);
-            project.ration_installation.deleteByRation(ration);
+            this.deleteSubListOfRation(ration);
             this.datas.splice(this.datas.indexOf(ration), 1);
         };
         ration.prototype.removeByID = function(ID){
@@ -420,9 +416,8 @@ var Ration = {
                        project.ration_glj.removeNodeByRation(recode.ration,projectObj.mainController);
                        project.Ration.deleteSubListOfRation(recode.ration);//删除旧定额下的相关记录
                        //添加新的记录
-                       project.ration_glj.addDatasToList(recode.ration_gljs);
-                       project.ration_coe.addDatasToList(recode.ration_coes);
-                       project.ration_installation.addDatasToList(recode.ration_installs);
+                       project.Ration.addSubListOfRation(recode);
+
 
                        project.ration_glj.addToMainTree(recode.ration_gljs);
                    }
@@ -507,10 +502,7 @@ var Ration = {
                     //更新缓存
                     for(let data of rstData){
                         me.datas.push(data.ration);
-                        project.ration_glj.addDatasToList(data.ration_gljs);
-                        project.ration_coe.addDatasToList(data.ration_coes);
-                        project.ration_installation.addDatasToList(data.ration_installs);
-
+                        me.addSubListOfRation(data);
                         //插入树节点
                         newSource = data.ration;
                         newNode = project.mainTree.insert(billItemID, nextID, newSource.ID);
@@ -605,9 +597,8 @@ var Ration = {
                 CommonAjax.post("/ration/addNewRation",{itemQuery:itemQuery,newData:newData,defaultLibID: rationLibObj.getDefaultStdRationLibID(),calQuantity:calQuantity,brUpdate:brUpdate,needInstall:needInstall},function (data) {
                     //更新缓存
                     me.datas.push(data.ration);
-                    project.ration_glj.addDatasToList(data.ration_gljs);
-                    project.ration_coe.addDatasToList(data.ration_coes);
-                    project.ration_installation.addDatasToList(data.ration_installs);
+
+                    me.addSubListOfRation(data);
 
                     //插入树节点
                     newSource = data.ration;
@@ -686,6 +677,7 @@ var Ration = {
                 CommonAjax.post("/ration/addNewRation",{itemQuery:null,newData:newData,defaultLibID: rationLibObj.getDefaultStdRationLibID(),calQuantity:false,brUpdate:brUpdate,needInstall:false},function (data) {
                     //更新缓存
                     me.datas.push(data.ration);
+                    me.addSubListOfRation(data);
                     //插入树节点
                     newSource = data.ration;
                     newNode.source = newSource;
@@ -705,7 +697,16 @@ var Ration = {
             projectObj.project.ration_coe.deleteByRation(ration);
             projectObj.project.quantity_detail.deleteByRation(ration);
             projectObj.project.ration_installation.deleteByRation(ration);
+            projectObj.project.ration_template.deleteByRation(ration);
+        };
+        ration.prototype.addSubListOfRation = function (data) {
+             project.ration_glj.addDatasToList(data.ration_gljs);
+             project.ration_coe.addDatasToList(data.ration_coes);
+             project.ration_installation.addDatasToList(data.ration_installations);
+             project.ration_template.addDatasToList(data.ration_templates);
+             project.quantity_detail.addDatasToList(data.quantity_details);
         };
+
         ration.prototype.replaceRation = function (ration, std) {
             this.project.beginUpdate('replaceRation');
             

+ 38 - 0
web/building_saas/main/js/models/ration_template.js

@@ -0,0 +1,38 @@
+/**
+ * Created by zhang on 2018/11/26.
+ */
+let ration_template = {
+    createNew: function (project) {
+        let ration_template = function (proj){
+            this.datas = [];
+
+            var sourceType = ModuleNames.ration_template;
+            this.getSourceType = function () {
+                return sourceType;
+            }
+            proj.registerModule(ModuleNames.ration_template, this);
+
+        };
+        // prototype用于定义public方法
+        ration_template.prototype.loadData = function (datas) {
+            this.datas = datas;
+        };
+        ration_template.prototype.addDatasToList = function (datas) {
+            let  me = this;
+            if(datas&&datas.length>0){
+                if (me.datas && Array.isArray(me.datas)) {
+                    me.datas = me.datas.concat(datas);
+                } else {
+                    me.datas = datas;
+                }
+            }
+        };
+        ration_template.prototype.getTemplateByRationID = function (rationID) {
+            return _.find(this.datas, {'rationID': rationID});
+        };
+        ration_template.prototype.deleteByRation = function(ration){
+            _.remove(this.datas,{'rationID':ration.ID});
+        };
+        return new ration_template(project);
+    }
+}

+ 3 - 2
web/building_saas/main/js/views/importBills.js

@@ -32,7 +32,7 @@ const importBills = (function(){
         serialNo: ['序号'],
         code: ['编码', '项目编码'],
         name: ['名称', '项目名称'],
-        itemCharacterText: ['特征', '项目特征'],
+        itemCharacterText: ['特征', '项目特征', '项目特征描述'],
         unit: ['单位', '计量单位'],
         quantity: ['工程量', '项目工程量'],
         money: ['金额'],
@@ -166,7 +166,8 @@ const importBills = (function(){
                 colMapping.name = colIdx;
             }
             //项目特征
-            else if(colMapping.itemCharacterText === undefined && (_deESC(cellData) === colText.itemCharacterText[0] || _deESC(cellData) === colText.itemCharacterText[1])){
+            else if(colMapping.itemCharacterText === undefined && (_deESC(cellData) === colText.itemCharacterText[0] || _deESC(cellData) === colText.itemCharacterText[1]
+                ||  _deESC(cellData) === colText.itemCharacterText[2])){
                 colMapping.itemCharacterText = colIdx;
             }
             //单位

+ 12 - 2
web/building_saas/main/js/views/installation_fee_view.js

@@ -712,7 +712,7 @@ let installationFeeObj={
             }
         }
     },
-    getBillDataForSelect:function () {//这里有个地方共用
+    getBillDataForSelect:function () {//这里有个地方共用
         let controller = projectObj.mainController, project = projectObj.project;
         let from = $('#calc_position_from').val();
         let rootNode = null,allNodes = [],datas = [],billID = null,selectedItem=null;
@@ -724,7 +724,17 @@ let installationFeeObj={
             let riSelection = this.modifyFeeRuleSheet.getSelections()[0];
             selectedItem = this.modifyFeeRuleData[riSelection.row];
             billID = selectedItem.billID;
-        }else {
+        }else if(from == "ration_template"){
+            let temSelection = mbzm_obj.sheet.getSelections()[0];
+            selectedItem = _.cloneDeep(mbzm_obj.datas[temSelection.row]);
+            if($('#createLocation').val() == 1) {//措施项目下
+                billID = selectedItem.billID;
+                selectedItem.feeType='措施费用'
+            } else {//分部分项下
+                billID = selectedItem.fxID;
+                selectedItem.feeType='分项费用'
+            }
+        } else {
             let selection = this.feeItemSheet.getSelections()[0];
             selectedItem = this.feeItemData[selection.row];
             if(from =="feeItemSheet"){

+ 92 - 12
web/building_saas/main/js/views/mbzm_view.js

@@ -4,35 +4,115 @@
 
 let mbzm_obj={
     spread:null,
+    nodeChanged:false,
+    datas:[],
     setting:{
         header: [
             {headerName: "编码", headerWidth: 130, dataCode: "code", dataType: "String", formatter: "@"},
-            {headerName: "模板类别", headerWidth: 260, dataCode: "templateType", dataType: "String", hAlign: "left"},
-            {headerName: "系数", headerWidth: 65, dataCode: "coe", dataType: "Number"},
+            {headerName: "模板类别", headerWidth: 260, dataCode: "name", dataType: "String", hAlign: "left"},
+            {headerName: "系数", headerWidth: 65, dataCode: "coe", dataType: "Number",validator:"number"},
             {headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center"},
-            {headerName: "工程量", headerWidth: 65, dataCode: "quantity", dataType: "Number",decimalField: "ration.quantity"},
+            {headerName: "工程量", headerWidth: 65, dataCode: "quantity", dataType: "Number",validator:"number"},
             {headerName: "关联类别", headerWidth: 100, dataCode: "type", dataType: "String"},
-            {headerName: "清单位置", headerWidth: 200, dataCode: "billsPosition", hAlign: "left", dataType: "String",cellType:'selectButton',getText:'forPosition'},
-            {headerName: "清单位置", headerWidth: 200, dataCode: "fxPosition", hAlign: "left", dataType: "String",cellType:'selectButton',getText:'forPosition',visible:false}
+            {headerName: "清单位置", headerWidth: 200, dataCode: "position", hAlign: "left", dataType: "String",cellType:'selectButton',getText:'forPosition'},
         ],
         view: {
-            lockColumns:["code","content","unit","type","billsPosition","fxPosition"],
+            lockColumns:["code","name","unit","type","fxID"],
             rowHeaderWidth:25
         },
-
+        getText:{
+            forPosition:function (item) {
+                let createL =  $('#createLocation').val();
+                if(createL == 1) return  mbzm_obj.getDisplayText(item.billID,item.billsLocation);
+                if(createL == 2) return  mbzm_obj.getDisplayText(item.fxID,"");
+                return ""
+            }
+        }
+    },
+    getDisplayText:function (billID,position) {
+        if(billID && billID!=''){
+            let node = projectObj.project.mainTree.getNodeByID(billID);
+            if(node){
+                let code = node.data.code?node.data.code:"";
+                let name = node.data.name?node.data.name:"";
+                return code +" "+name;
+            }
+        }
+        return  position;
     },
+    //当点击应用的时候才保存数据
     initSpread:function () {
         this.spread = SheetDataHelper.createNewSpread($("#mbzmSpread")[0]);
         sheetCommonObj.spreadDefaultStyle(this.spread);
         this.sheet = this.spread.getSheet(0);
         sheetCommonObj.initSheet(this.sheet, this.setting);
-        this.sheet.setRowCount(0);
-
+        this.sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange);
+        this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, installationFeeObj.onPositionButtonClick);//共用一个位置选择器
+        this.sheet.name('ration_template');
     },
     refresh:function () {
-        this.spread?this.spread.refresh():'';
+        let total = $('#mbzmSpread').parent().height();
+        let b_height = $('#mbzmSpread').prev('.col-12').height();
+        $('#mbzmSpread').css('height',total- b_height);
+        this.spread?this.spread.refresh():this.initSpread();
+    },
+    refreshSheetData:function () {
+        sheetCommonObj.showData(this.sheet, this.setting,this.datas);
     },
     showMBZMData:function(node){
-       let selected = node?node:projectObj.project.mainTree.selected;
+        let selected = node?node:projectObj.project.mainTree.selected;
+        if(this.nodeChanged == true){//选中的行改变了才做初始化,刷新当前缓存, 在project_view 中treeSelectedChanged方法里设置
+            let datas = [];
+            $("#createLocation").val(1);//初始化
+            if(selected&&selected.sourceType == "ration"){
+                let ration = selected.data;
+                let  template = projectObj.project.ration_template.getTemplateByRationID(ration.ID);
+                if(template) {
+                    $("#createLocation").val(template.createLocation);
+                    let pcol = _.findIndex(this.setting.header,{dataCode:"position"});
+                    this.setting.header[pcol].visible = template.createLocation == 3?false:true;
+                    datas = _.cloneDeep(template.templateList);
+                }
+            }
+            this.datas = datas;
+            this.nodeChanged = false;//这里要恢复成false 应为调用gljObj.refresh() 方法也会进到这里来,这时节点应是没有改变的
+        }
+        sheetCommonObj.showData(this.sheet, this.setting,this.datas);
+        this.sheet.setRowCount(this.datas.length);
+    },
+    onSheetValueChange:function (e,info) {
+        let me = mbzm_obj;
+        let selected = projectObj.project.mainTree.selected;
+        let row = info.row, col = info.col;
+        let dataCode = me.setting.header[col].dataCode;
+        let recode = me.datas[row], value = info.newValue;
+        if (info.newValue === undefined) {
+            return;
+        }
+        if (value && !sheetCommonObj.checkData(col, me.setting, value)) {
+            alert('输入的数据类型不对,请重新输入!');
+            me.refreshSheetData();
+            return;
+        }
+        if (dataCode === 'coe') {//默认为0,可输入数值,输入数值后,后面的工程量=混凝土子目工程量*系数。
+            let rationQuantity = selected.data.quantity;
+            rationQuantity = rationQuantity?scMathUtil.roundForObj(rationQuantity, getDecimal('ration.quantity')):0;
+            value = scMathUtil.roundForObj(value, getDecimal('process'));
+            recode["quantity"] = scMathUtil.roundForObj(rationQuantity * value, getDecimal('ration.quantity'))+"";
+        }
+        if (dataCode === 'quantity') {//定额默认显示为0,可输入数值,输入数值后,则清空前面的系数列
+            value = scMathUtil.roundForObj(value, getDecimal('ration.quantity'))+"";
+            recode["coe"] = "0";
+        }
+        recode[dataCode] = value;
+        me.refreshSheetData();
     }
-}
+};
+
+$('#createLocation').change(function(){
+    let me = mbzm_obj;
+    let pcol = _.findIndex(me.setting.header,{dataCode:"position"});
+    me.setting.header[pcol].visible =  $(this).val() == 3?false:true;
+    me.refreshSheetData();
+
+});

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

@@ -32,6 +32,7 @@ var projectObj = {
             refreshNodes.push(project.mainTree.preSelected);
             init = !(project.mainTree.preSelected == node)
         }
+        mbzm_obj.nodeChanged = init;
         project.mainTree.preSelected = node;
         projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes);
         if($('#linkComments').hasClass('active')){

+ 2 - 8
web/building_saas/main/js/views/sub_view.js

@@ -77,8 +77,8 @@ let subObj = {
             installationFeeObj.engineeringTypeChecking();//检查是否安装工程
             $("#TZJNR_div").hide();
   			$('#QDJL_div').hide();
-            $("#linkGLJ").addClass();            $(gljOprObj.rationTab).click();
-
+            $("#linkGLJ").addClass();
+            $(gljOprObj.rationTab).click();
         }else {
             $("#GLJ_div").hide();
             $("#ZMHS_div").hide();
@@ -618,12 +618,6 @@ $('#linkZMHS').on('shown.bs.tab', function (e) {
 
 
 $('#linkMBZM').on('shown.bs.tab', function (e) {
-    let total = $('#mbzmSpread').parent().height();
-    let b_height = $('#mbzmSpread').prev('.col-12').height();
-    $('#mbzmSpread').css('height',total- b_height);
-    if(mbzm_obj.spread == null){
-        mbzm_obj.initSpread();
-    }
     mbzm_obj.refresh();
     mbzm_obj.showMBZMData();
 });

+ 56 - 5
web/building_saas/pm/html/project-management.html

@@ -31,6 +31,12 @@
         #summary-engineering,#summary-project{
             display: none;
         }
+        #shareToInfo {
+            display:block;
+            height:200px;
+            overflow-y:auto;
+            -webkit-overflow-scrolling: touch;
+        }
     </style>
 </head>
 
@@ -631,6 +637,51 @@
 </div>
 <!--弹出分享-->
 <div class="modal fade" id="share" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">分享给...</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <!--添加分享-->
+                <div class="form-group">
+                    <div class="input-group input-group-sm">
+                        <input id="sharePhone" type="text" class="form-control" placeholder="输入 手机号 添加分享">
+                       <!-- <div class="input-group-append">
+                            <button class="btn btn-primary" type="button" id="button-addon2">添加分享</button>
+                        </div>-->
+                    </div>
+                </div>
+                <table class="table table-sm" id="shareFindDiv">
+                    <tbody style="display: block">
+                    <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">添加分享</th></tr>
+                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
+                    </tbody>
+                </table>
+                <p id="share-info" class="text-danger">不存在手机号 15812777651 的用户</p>
+                <!--已分享数据-->
+                <legend>已分享</legend>
+                <table class="table table-sm">
+                    <tbody id="shareToInfo">
+                    <tr><th>姓名</th><th>公司</th><th>手机</th><th>邮箱</th><th width="90">允许拷贝</th><th width="90">取消分享</th></tr>
+                    <tr><td>张三</td><td>XX公司</td><td>12345678900</td><td></td><td><input type="checkbox"></td><td><input type="checkbox"></td></tr>
+                    <tr><td>王五</td><td>XX公司</td><td>12345678900</td><td></td><td><input type="checkbox"></td><td><input type="checkbox"></td></tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <!--分享人可以取消-->
+                <button id="shareToConfirm" type="button" class="btn btn-primary" data-dismiss="modal">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--弹出分享-->
+<!--<div class="modal fade" id="share" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
@@ -660,7 +711,7 @@
                             <div class="form-check mb-2">
                                 <input type="checkbox" class="form-check-input" id="allowCopy">
                                 <label class="form-check-label" for="allowCopy">允许该用户拷贝该工程</label>
-                                <!--打勾后出现提示-->
+                                &lt;!&ndash;打勾后出现提示&ndash;&gt;
                                 <div id="allowCopyHint" class="form-text text-danger"><i class="fa fa-exclamation-triangle"></i> 该用户可以把你的项目拷贝成为他的数据,请谨慎勾选。 </div>
                             </div>
                             <a id="addShareUser" class="btn btn-sm btn-primary" href="javascript:void(0);"><i class="fa fa-plus"></i> 添加</a>
@@ -679,9 +730,9 @@
             </div>
         </div>
     </div>
-</div>
+</div>-->
 <!--弹出分享给交互-->
-<div class="modal fade" id="shareTo" data-backdrop="static">
+<!--<div class="modal fade" id="shareTo" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content" style="width: 750px;">
             <div class="modal-header">
@@ -691,7 +742,7 @@
                 </button>
             </div>
             <div class="modal-body modal-fixed-height">
-                <!--     <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>-->
+                &lt;!&ndash;     <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>&ndash;&gt;
                 <table class="table table-hover table-sm mb-5">
                     <thead>
                     <tr style="display: block;">
@@ -721,7 +772,7 @@
             </div>
         </div>
     </div>
-</div>
+</div>-->
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script>GC.Spread.Sheets.LicenseKey = '<%- LicenseKey %>';</script>

+ 59 - 124
web/building_saas/pm/js/pm_newMain.js

@@ -35,9 +35,6 @@ let taxTypeMap = {
 * */
 let regions = [];
 
-//分享用户列表
-let shareUsers = [];
-
 function isDef(v) {
     return typeof v !== 'undefined' && v !== null;
 }
@@ -308,9 +305,11 @@ const projTreeObj = {
                         //return !(selectedItem && selectedItem.data.projType === projectType.tender);
                     },
                     callback: function (key, opt) {
+                        let selected = projTreeObj.tree.selected;
                         $('#sharePhone').val('');
                         $('#share-info').hide();
-                        $('#share').find('.card').hide();
+                        $('#shareFindDiv').hide();
+                        setShareToModal(selected);
                         $('#share').modal('show');
                         //默认允许拷贝
                         $('#allowCopy').prop('checked', true);
@@ -320,7 +319,7 @@ const projTreeObj = {
                         }, 200);
                     }
                 },
-                'cancelShare': {
+               /* 'cancelShare': {
                     name: '取消分享',
                     icon: 'fa-ban',
                     disabled: function () {
@@ -332,7 +331,7 @@ const projTreeObj = {
                         setShareToModal(selected);
                         $('#shareTo').modal('show');
                     }
-                },
+                },*/
                 "spr3": '--------',
                 "manageFiles": {
                     name: "管理相关文件",
@@ -1902,7 +1901,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             let updateProjs = GetUpdateData(pre, parent, next, projName, null, projID, {updateType: 'new', projectType: projectType.project});
             let updateEng = {updateType: 'new', updateData: {ID: engID, ParentID: projID, NextSiblingID: -1, name: engName, projType: projectType.engineering}};
             property.rootProjectID = projID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
             updateDatas = updateDatas.concat(updateProjs);
             updateDatas.push(updateEng);
             updateDatas.push(updateTender);
@@ -1937,7 +1936,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             let next = null;
             let updateEng = {updateType: 'new', updateData: {ID: engID, ParentID: tempProj.data.ID, NextSiblingID: -1, name: engName, projType: projectType.engineering}};
             property.rootProjectID = tempProj.data.ID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1,  shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
             if(selected && selected.data.projType === projectType.engineering && selected.parent === tempProj){
                 pre = selected;
                 next = selected.nextSibling;
@@ -1973,7 +1972,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             let tenderID = IDs.lowID;
             let pre = tempEng.lastChild();
             property.rootProjectID = tempProj.data.ID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: tempEng.id(), NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: tempEng.id(), NextSiblingID: -1,  shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
             updateDatas.push(updateTender);
             if(pre){
                 updateDatas.push({updateType: 'update', updateData: {ID: pre.id(), NextSiblingID: tenderID}});
@@ -3321,9 +3320,11 @@ function shareTender(){
     canShare = false;
     let phone = $('#sharePhone').val();
     const hintInfo = $('#share-info');
-    const userInfo = $('#share').find('.card');
+    const userInfo = $('#shareFindDiv');
     const addUser = $('#addShareUser');
     const copyInput = $('#allowCopy');
+    const shareConfirm = $('#share-confirm');
+    shareConfirm.addClass('disabled');
     //可分享才可添加用户
     addUser.addClass('disabled');
     if (hintInfo.is(':visible')) {
@@ -3354,10 +3355,8 @@ function shareTender(){
             setDangerInfo(hintInfo, '', false);
             $('#user_name').text(userData.real_name ? userData.real_name : '');
             $('#user_company').text(userData.company ? userData.company : '');
-            let mobileHtml = `<i class="fa fa-tablet"> ${userData.mobile ? userData.mobile : ''}</i>`;
-            $('#user_mobile').html(mobileHtml);
-            let emailHtml = `<i class="fa fa-envelope-o"> ${userData.email ? userData.email : ''}</i>`;
-            $('#user_email').html(emailHtml);
+            $('#user_mobile').text(userData.mobile ? userData.mobile : '');
+            $('#user_email').text(userData.email ? userData.email : '');
             //默认可拷贝
             copyInput.prop('checked', true);
             userInfo.show();
@@ -3370,6 +3369,7 @@ function shareTender(){
                     }
                 }
                 addUser.removeClass('disabled');
+                shareConfirm.removeClass('disabled');
                 canShare = true;
             });
         }
@@ -3381,127 +3381,46 @@ $('#sharePhone').on('keyup',function () {
     });
 });
 
-//设置确认分享用户列表
-//@param {String}name {String}phone @return {void}
-function setUsersShareDiv(projName, users) {
-    //每行的数据
-    const perLineCount = 2;
-    let $users = $('#shareUsers');
-    //三行后限制死高度
-    if (Math.ceil(users.length / perLineCount) > 2) {
-        $users.height(180);
-    } else {
-        $users.height('');
-    }
-    $users.empty();
-    let $projInfo = $(`<p>确认分享 <b>${projName}</b> 给</p>`);
-    $users.append($projInfo);
-    let $preP = null,
-        $preH4 = null;
-    for (let i = 0; i < users.length; i++) {
-        let user = users[i];
-        let $span = $(`<span class="badge badge-light mr-3" style="padding: 0">${user.name}(${user.phone})</span>`),
-            $a = $(`<a href="javascript:void(0);" userID="${user.userID}" class="text-danger" title="移除分享"></a>`),
-            $i = $('<i class="fa fa-remove"></i>');
-        bindRemoveShare($a);
-        $a.append($i);
-        $span.append($a);
-        //另起一行
-        if (i % 2 === 0) {
-           $preP = $('<p>');
-           $preH4 = $('<h4>');
-           $preH4.append($span);
-           $preP.append($preH4);
-           $users.append($preP);
-        } else {//行内新增元素
-            $preH4.append($span);
-            $preP.append($preH4);
-        }
-    }
-    if (users.length > 0) {
-        $users.show();
-    }
-    //移除分享列表
-    function bindRemoveShare(a){
-        a.click(function () {
-            let theUserID = a.attr('userID');
-            //清除shareUsers数组相关数据
-            _.remove(shareUsers, {userID: theUserID});
-            a.parent().remove();
-            //如果行内只剩一个数据,则删除数据及行
-            if (a.parent().parent().children().length === 0) {
-                a.parent().parent().remove();
-            }
-            //如果所用用户数据只剩这一条,删除用户数据则隐藏分享用户列表容器
-            if (shareUsers.length === 0) {
-                $('#shareUsers').hide();
-            }
-        });
-    }
-
-}
-//添加分享用户
-$('#addShareUser').click(function () {
-    //输入有效手机号的用户
-    if (shareUserID) {
-        const hintInfo = $('#share-info');
-        if (_.find(shareUsers, {userID: shareUserID})) {
-            setDangerInfo(hintInfo, '已添加此用户');
-            return;
-        }
-        let allowCopy = $('#allowCopy').prop('checked'),
-            name = $('#user_name').text(),
-            phone = $('#user_mobile').text();
-        shareUsers.push({userID: shareUserID, name: name, phone: phone, allowCopy: allowCopy});
-        let selected = projTreeObj.tree.selected;
-        setUsersShareDiv(selected.data.name, shareUsers);
-        if (hintInfo.is(':visible')) {
-            hintInfo.hide();
-        }
-        //搜索的用户信息
-        $('#share').find('.card').hide();
-        $('#sharePhone').val('');
-        $('#sharePhone').focus();
-        shareUserID = null;
-    }
-});
-$('#share').on('hidden.bs.modal', function () {
-    $('#shareUsers').hide();
-    shareUsers = []
-});
 //确认分享
 $('#share-confirm').click(function(){
     const hintInfo = $('#share-info');
-    if (shareUsers.length === 0) {
-        setDangerInfo(hintInfo, '请添加分享');
-        return;
-    }
-    $('#shareUsers').hide();
-    $('#share-confirm').addClass('disabled');
     $.bootstrapLoading.start();
-    let allowCopy = $('#allowCopy').prop('checked');
-    let shareData = [];
-    for (let userData of shareUsers) {
-        shareData.push({userID: userData.userID, allowCopy: userData.allowCopy});
-    }
+    const perHeight = 30;
+    let allowCopy = $('#allowCopy').prop('checked'),
+        userName = $('#user_name').text() || '',
+        userCompany = $('#user_company').text() || '',
+        userMobile = $('#user_mobile').text() || '',
+        userEmail = $('#user_email').text() || '';
+    let shareData = [{userID: shareUserID, allowCopy: allowCopy}];
     //分享
     CommonAjax.post('/pm/api/share', {user_id: userID, type: shareType.create,  projectID: shareSeleted.data.ID, shareData: shareData}, function (rstData) {
+        //更新已分享table
+        let $tr = $(`<tr>
+                        <td style="width: 112px">${userName}</td>
+                        <td style="width: 165px">${userCompany}</td>
+                        <td style="width: 136px">${userMobile}</td>
+                        <td style="width: 136px">${userEmail}</td>
+                        <td style="width: 90px;"><input value="allowCopy" ${allowCopy ? 'checked' : ''} type="checkbox"></td>
+                        <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
+                     </tr>`);
+        let tbodyTotalHeight = $('#shareToInfo').height() + perHeight > 200 ? 200 : $('#shareToInfo').height() + perHeight;
+        $('#shareToInfo').height(tbodyTotalHeight);
+        $('#shareToInfo').append($tr);
         //更新缓存
-        if (shareSeleted.data.shareInfo.length === 0) {
+       // if (shareSeleted.data.shareInfo.length === 0) {
             shareSeleted.data.shareInfo = shareSeleted.data.shareInfo.concat(shareData);
             let sheet = projTreeObj.workBook.getSheet(0);
             projTreeObj.renderSheetFuc(sheet, function () {
                 sheet.invalidateLayout();
                 sheet.repaint();
             });
-        }
+       // }
         $.bootstrapLoading.end();
-        $('#share-confirm').removeClass('disabled');
-        $('#share').modal('hide');
+        $('#shareFindDiv').hide();
+        $('#share-confirm').addClass('disabled');
     }, function () {
         $.bootstrapLoading.end();
         $('#share-confirm').removeClass('disabled');
-        $('#share').modal('hide');
     });
 });
 //允许拷贝
@@ -3527,6 +3446,7 @@ $('#shareToConfirm').click(function () {
 //设置分享给界面数据
 //@param {Object}selected @return {void}
 function setShareToModal(selected){
+    const perHeight = 30; //每条分享给数据的高度
     $('#shareToInfo').empty();
     if(!selected){
         return;
@@ -3547,17 +3467,29 @@ function setShareToModal(selected){
             }
         }
         let infoArr = [];
+        //居中style="width: 90px;text-align: center"
+        let theadHtml = `<tr>
+                                          <th style="width: 112px;">姓名</th>
+                                          <th style="width: 165px;">公司</th>
+                                          <th style="width: 136px;">手机</th>
+                                          <th style="width: 136px;">邮箱</th>
+                                          <th style="width: 90px;">允许拷贝</th>
+                                          <th style="width: 90px;">取消分享</th>
+                               </tr>`;
+        infoArr.push(theadHtml);
         for(let user of selected.data.shareInfo){
             let infoHtml = `<tr>
-                                          <td style="width: 106px;">${user.name}</td>
-                                          <td style="width: 146px;">${user.company}</td>
-                                          <td style="width: 146px;">${user.mobile}</td>
-                                          <td style="width: 156px;">${user.email}</td>
-                                          <td style="width: 70px;text-align: center"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
-                                          <td style="width: 70px;text-align: center"><input value="cancelShare" type="checkbox"></td>
+                                          <td style="width: 112px;">${user.name}</td>
+                                          <td style="width: 165px;">${user.company}</td>
+                                          <td style="width: 136px;">${user.mobile}</td>
+                                          <td style="width: 160px;">${user.email}</td>
+                                          <td style="width: 90px;"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
+                                          <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
                                </tr>`;
             infoArr.push(infoHtml);
         }
+        let tbodyTotalHeight = infoArr.length * perHeight + 5 > 200 ? 200 : infoArr.length * perHeight + 5;
+        $('#shareToInfo').height(tbodyTotalHeight);
         let infoHtml = infoArr.join('');
         $('#shareToInfo').html(infoHtml);
     });
@@ -3569,6 +3501,9 @@ function updateShareInfo(selected){
         return;
     }
     let usersTr = $('#shareToInfo').find('tr');
+    if (usersTr && usersTr.length > 0) {
+        usersTr = usersTr.slice(1);
+    }
     let newShareInfo = [];
     for(let i = 0; i < usersTr.length; i++){
         let userTr = usersTr[i];

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

@@ -65,7 +65,7 @@ let zTreeOprObj = {
         let private_chk_hide = function (chkTplItem) {
             //考虑未来拓展,统一在此判断报表模板是否显示
             let rst = false;
-            if (chkTplItem.hasOwnProperty('flags') && chkTplItem.flags.hasOwnProperty('taxType') &&
+            if (chkTplItem.hasOwnProperty('flags') && chkTplItem.flags.hasOwnProperty('taxType') && chkTplItem.flags['taxType'] !== null &&
                 parseInt(chkTplItem.flags['taxType']) !== parseInt(projectInfoObj.projectInfo.property.taxType)) {
                 rst = true;
             }