Bladeren bron

Merge branch '1.0.0_online' of http://192.168.1.41:3000/SmartCost/ConstructionCost into 1.0.0_online

TonyKang 6 jaren geleden
bovenliggende
commit
738a297e01
67 gewijzigde bestanden met toevoegingen van 6194 en 618 verwijderingen
  1. 4 0
      config/gulpConfig.js
  2. 15 0
      lib/js-zip/jszip.min.js
  3. 8 1
      modules/all_models/bills.js
  4. 25 0
      modules/all_models/engineering_lib.js
  5. 4 0
      modules/all_models/project_glj.js
  6. 1 0
      modules/all_models/projects.js
  7. 5 0
      modules/all_models/stdBills_bills.js
  8. 25 0
      modules/all_models/std_economic_lib.js
  9. 25 0
      modules/all_models/std_engineer_feature_lib.js
  10. 25 0
      modules/all_models/std_engineer_info_lib.js
  11. 4 0
      modules/all_models/std_glj.js
  12. 25 0
      modules/all_models/std_main_quantity_lib.js
  13. 25 0
      modules/all_models/std_material_lib.js
  14. 3 1
      modules/common/const/bills_fixed.js
  15. 6 2
      modules/glj/models/glj_list_model.js
  16. 1 1
      modules/glj/models/mix_ratio_model.js
  17. 32 0
      modules/main/controllers/project_controller.js
  18. 108 1
      modules/main/facade/project_facade.js
  19. 3 0
      modules/main/facade/ration_facade.js
  20. 9 3
      modules/main/models/bills.js
  21. 7 3
      modules/main/models/ration.js
  22. 8 1
      modules/main/routes/main_route.js
  23. 2 1
      modules/main/routes/project_route.js
  24. 50 4
      modules/pm/controllers/pm_controller.js
  25. 370 5
      modules/pm/facade/pm_facade.js
  26. 45 18
      modules/pm/models/project_model.js
  27. 3 1
      modules/pm/models/project_property_template.js
  28. 6 0
      modules/pm/routes/pm_route.js
  29. 3 0
      modules/ration_glj/facade/ration_glj_facade.js
  30. 10 0
      modules/templates/controllers/bills_template_controller.js
  31. 88 0
      modules/templates/models/bills_template.js
  32. 1 0
      modules/templates/routes/bills_template_router.js
  33. 4 1
      public/counter/counter.js
  34. 2 2
      public/gljUtil.js
  35. 56 0
      public/web/PerfectLoad.js
  36. 4 4
      public/web/gljUtil.js
  37. 139 6
      public/web/sheet/sheet_common.js
  38. 2 1
      public/web/tree_sheet/tree_sheet_helper.js
  39. 4 2
      web/building_saas/css/custom.css
  40. 11 1
      web/building_saas/css/main.css
  41. 12 12
      web/building_saas/glj/html/project_glj.html
  42. 10 2
      web/building_saas/js/global.js
  43. 28 0
      web/building_saas/main/html/index_info.html
  44. 119 1
      web/building_saas/main/html/main.html
  45. 29 0
      web/building_saas/main/js/models/bills.js
  46. 2 1
      web/building_saas/main/js/models/cache_tree.js
  47. 23 2
      web/building_saas/main/js/models/calc_base.js
  48. 0 1
      web/building_saas/main/js/models/calc_program.js
  49. 569 0
      web/building_saas/main/js/models/exportSEIInterface.js
  50. 780 223
      web/building_saas/main/js/models/exportStandardInterface.js
  51. 1506 36
      web/building_saas/main/js/models/importStandardInterface.js
  52. 3 1
      web/building_saas/main/js/models/main_consts.js
  53. 25 16
      web/building_saas/main/js/models/project.js
  54. 5 4
      web/building_saas/main/js/models/project_glj.js
  55. 12 0
      web/building_saas/main/js/models/ration_glj.js
  56. 206 0
      web/building_saas/main/js/views/export_view.js
  57. 1 1
      web/building_saas/main/js/views/fee_rate_view.js
  58. 725 0
      web/building_saas/main/js/views/index_view.js
  59. 14 1
      web/building_saas/main/js/views/main_tree_col.js
  60. 106 31
      web/building_saas/main/js/views/material_adjust_view.js
  61. 6 3
      web/building_saas/main/js/views/project_glj_view.js
  62. 47 16
      web/building_saas/main/js/views/project_view.js
  63. 80 44
      web/building_saas/pm/html/project-management.html
  64. 7 1
      web/building_saas/pm/js/pm_ajax.js
  65. 365 20
      web/building_saas/pm/js/pm_import.js
  66. 345 142
      web/building_saas/pm/js/pm_newMain.js
  67. 1 1
      web/over_write/js/chongqing_2018.js

+ 4 - 0
config/gulpConfig.js

@@ -49,6 +49,7 @@ module.exports = {
         'lib/JSExpressionEval_src/Date.js',
         'web/building_saas/glj/js/socket.io.slim.js',
         'public/web/socket/connection.js',
+        'web/building_saas/main/js/models/importStandardInterface.js',
         'web/building_saas/pm/js/**/*.js',
         'lib/ztree/*.js',
         'lib/jquery-contextmenu/jquery.contextMenu.min.js'
@@ -110,6 +111,7 @@ module.exports = {
         'web/building_saas/main/js/models/cache_tree.js',
         'web/building_saas/main/js/calc/calc_fees.js',
         'web/building_saas/main/js/models/exportStandardInterface.js',
+        'web/building_saas/main/js/models/exportSEIInterface.js',
         // 'web/building_saas/main/js/calc/ration_calc.js',
         // 'web/building_saas/main/js/calc/bills_calc.js',
         // 'public/calc_util.js',
@@ -119,6 +121,7 @@ module.exports = {
         'web/building_saas/main/js/views/glj_col.js',
         'web/building_saas/main/js/views/main_tree_col.js',
         'web/building_saas/main/js/views/project_info.js',
+        'web/building_saas/main/js/views/export_view.js',
         'web/building_saas/main/js/views/project_view.js',
         'web/building_saas/main/js/views/options_view.js',
         'web/building_saas/main/js/views/project_property_bills_quantity_decimal.js',
@@ -144,6 +147,7 @@ module.exports = {
         'web/building_saas/main/js/views/zlfb_view.js',
         'web/building_saas/main/js/views/installation_fee_view.js',
         'web/building_saas/main/js/views/material_adjust_view.js',
+        'web/building_saas/main/js/views/index_view.js',
         'web/building_saas/main/js/views/project_glj_view.js',
         'web/building_saas/main/js/views/importBills.js',
         'public/web/rpt_tpl_def.js',

File diff suppressed because it is too large
+ 15 - 0
lib/js-zip/jszip.min.js


+ 8 - 1
modules/all_models/bills.js

@@ -65,10 +65,17 @@ let billsSchema = new Schema({
     deleteInfo: deleteSchema,
     isEstimate:{type: Number,default:0},       // 1 true 0 false 是否暂估
     mainBills:{type:Schema.Types.Mixed,default:false},//true 是,false否,null 不确定,三个状态
+    outPutMaxPrice:{type:Schema.Types.Mixed,default:false},//输出最高限价 true 是,false否,null 不确定,三个状态
+    maxPrice:String,//最高限价
     remark:String,
     engineeringContent:String,//工程内容
     serviceContent:String,//服务内容
-    claimVisa:String//签证及索赔依据
+    claimVisa:String,//签证及索赔依据
+    //经济指标属性
+    economicType:String,//工程经济指标类别
+    quantityIndexType:String,//工程量指标类别
+    quantityIndexUnit:String,//工程量指标单位
+    quantityIndexCoe:Number//单位转换系数
 });
 
 mongoose.model("bills", billsSchema);

+ 25 - 0
modules/all_models/engineering_lib.js

@@ -62,6 +62,30 @@ let modelSchema = {
         type: Schema.Types.Mixed,
         default: []
     },
+    engineer_info_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    //工程特征指标库
+    engineer_feature_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    //主要工料指标库
+    material_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    //主要工程量指标库
+    main_quantity_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    //主要经济指标库
+    economic_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
     //设置人材机显示列
     glj_col:{
         showAdjustPrice:Boolean//是否显示调整价列
@@ -78,6 +102,7 @@ let modelSchema = {
     engineering:Number,
     //是否计算安装增加费
     isInstall:{type: Boolean, default: false},
+    indexName:String,//指标专业名称
     seq:Number//序列号
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 4 - 0
modules/all_models/project_glj.js

@@ -106,6 +106,10 @@ let modelSchema = {
     connect_code: String,
     materialType: Number,//三材类别
     materialCoe: Number,//三材系数
+    //经济指标数据
+    materialIndexType:String,//工料指标类别
+    materialIndexUnit:String,//工料指标单位
+    materialIndexCoe:Number,//单位转换系数
     // 是否主要材料 (0为否 1为是)
     is_main_material: {
         type: Number,

+ 1 - 0
modules/all_models/projects.js

@@ -18,6 +18,7 @@ const ProjectSchema = new Schema({
     "ParentID": Number,
     "NextSiblingID": Number,
     "userID": String,
+    "code": {type: String, default: ''},
     "name": String,
     "projType": String,
     "recentDateTime": Date,

+ 5 - 0
modules/all_models/stdBills_bills.js

@@ -19,6 +19,11 @@ const stdBills_bills = new Schema({
             items: [],
             recharge:String,
             billsLibId: {type:Number, index: true},
+            //经济指标属性
+            economicType:String,//工程经济指标类别
+            quantityIndexType:String,//工程量指标类别
+            quantityIndexUnit:String,//工程量指标单位
+            quantityIndexCoe:Number,//单位转换系数
             deleted: Boolean
     },
     {versionKey: false}

+ 25 - 0
modules/all_models/std_economic_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//主要工程量指标库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const economicLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    index: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+}, {versionKey: false});
+mongoose.model('std_economic_lib', economicLib, 'std_economic_lib');

+ 25 - 0
modules/all_models/std_engineer_feature_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//建设项目基本信息库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const engineerFeatureLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    features: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+}, {versionKey: false});
+mongoose.model('std_engineer_feature_lib', engineerFeatureLib, 'std_engineer_feature_lib');

+ 25 - 0
modules/all_models/std_engineer_info_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//建设工程信息指标库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const engineerInfoLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    info: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+}, {versionKey: false});
+mongoose.model('std_engineer_info_lib', engineerInfoLib, 'std_engineer_info_lib');

+ 4 - 0
modules/all_models/std_glj.js

@@ -38,6 +38,10 @@ const std_glj = new Schema({
     adjCoe: Number,
     materialType: Number,   //三材类别
     materialCoe: Number,    //三材系数
+    //经济指标数据
+    materialIndexType:String,//工料指标类别
+    materialIndexUnit:String,//工料指标单位
+    materialIndexCoe:Number,//单位转换系数
     component: [std_gljComponent]
 },{versionKey: false});
 

+ 25 - 0
modules/all_models/std_main_quantity_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//主要工程量指标库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const quantityLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    index: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+}, {versionKey: false});
+mongoose.model('std_main_quantity_lib', quantityLib, 'std_main_quantity_lib');

+ 25 - 0
modules/all_models/std_material_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//建设项目基本信息库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const materialLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    materials: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+}, {versionKey: false});
+mongoose.model('std_material_lib', materialLib, 'std_material_lib');

+ 3 - 1
modules/common/const/bills_fixed.js

@@ -62,7 +62,9 @@ const fixedFlag = {
     //建设工程竣工档案编制费
     PROJECT_COMPLETE_ARCH_FEE:30,
     //住宅工程质量分户验收费
-    HOUSE_QUALITY_ACCEPT_FEE:31
+    HOUSE_QUALITY_ACCEPT_FEE:31,
+    //组织措施费
+    ORGANIZATION:32
 };
 
 export default fixedFlag;

+ 6 - 2
modules/glj/models/glj_list_model.js

@@ -61,7 +61,7 @@ class GLJListModel extends BaseModel {
         switch (scene) {
             // 新增数据的验证规则
             case 'add':
-                this.model.schema.path('glj_id').required(true);
+                //this.model.schema.path('glj_id').required(true);
                 this.model.schema.path('project_id').required(true);
                 this.model.schema.path('code').required(true);
                 // this.model.schema.path('name').required(true);
@@ -84,6 +84,7 @@ class GLJListModel extends BaseModel {
         let mixRationMap={};
         let keyMap={};
         let unitPriceList={};
+        unitPriceFileId = unitPriceFileId?unitPriceFileId:await ProjectModel.getUnitPriceFileId(projectId);
         try {
             // 首先获取对应标段下所有的项目工料机数据
             let condition = {project_id: projectId};
@@ -602,7 +603,10 @@ class GLJListModel extends BaseModel {
                     adjCoe:tmp.adjCoe,
                     original_code:tmp.code,
                     materialType: tmp.materialType,   //三材类别
-                    materialCoe: tmp.materialCoe
+                    materialCoe: tmp.materialCoe,
+                    materialIndexType: tmp.materialIndexType,
+                    materialIndexUnit: tmp.materialIndexUnit,
+                    materialIndexCoe: tmp.materialIndexCoe
                 };
                 gljInsertData.push(gljData);
             }

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

@@ -33,7 +33,7 @@ class MixRatioModel extends BaseModel {
         switch (scene) {
             // 新增数据的验证规则
             case 'add':
-                this.model.schema.path('glj_id').required(true);
+                //this.model.schema.path('glj_id').required(true);
                 this.model.schema.path('consumption').required(true);
                 this.model.schema.path('unit_price_file_id').required(true);
                 this.model.schema.path('connect_key').required(true);

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

@@ -151,5 +151,37 @@ module.exports = {
             result.message = err.message;
         }
         res.json(result);
+    },
+    getSEIProjects:async function(req,res){
+        let data = JSON.parse(req.body.data);
+        let result={
+            error: 0,
+            data: null
+        };
+        try{
+            result.data = await project_facade.getSEIProjects(data.projectID);
+        }
+        catch(err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    },
+    loadSEIProjectData:async function(req,res){
+        let data = JSON.parse(req.body.data);
+        let result={
+            error: 0,
+            data: null
+        };
+        try{
+            result.data = await project_facade.loadSEIProjectData(data.projectID);
+        }
+        catch(err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
     }
 };

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

@@ -9,7 +9,10 @@ module.exports = {
     calcInstallationFee:calcInstallationFee,
     saveProperty: saveProperty,
     getDefaultColSetting: getDefaultColSetting,
-    markProjectsToChange:markProjectsToChange
+    markProjectsToChange:markProjectsToChange,
+    getSEIProjects:getSEIProjects,
+    loadSEIProjectData:loadSEIProjectData,
+    setSEILibData:setSEILibData
 };
 
 let mongoose = require('mongoose');
@@ -28,6 +31,12 @@ let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
 const uuidV1 = require('uuid/v1');
 const gljUtil = require('../../../public/gljUtil');
 let stdColSettingModel = mongoose.model('std_main_col_lib');
+import GLJListModel from "../../glj/models/glj_list_model";
+let economicLib = mongoose.model('std_economic_lib');
+let engineerFeatureLib = mongoose.model('std_engineer_feature_lib');
+let engineerInfoLib = mongoose.model('std_engineer_info_lib');
+let mainQuantityLib = mongoose.model('std_main_quantity_lib');
+let materialLib = mongoose.model('std_material_lib');
 
 
 
@@ -274,4 +283,102 @@ function saveProperty(data, callback){
 
 async function getDefaultColSetting(libID){
     return await stdColSettingModel.findOne({ID: libID, deleted: false}, '-_id main_tree_col');
+}
+
+function sortChildren(lists) {
+    let IDMap ={},nextMap = {}, firstNode = null,newList=[];
+    for(let l of lists){
+        if(l.children&&l.children.length > 0) l.children = sortChildren(l.children);//递规排序
+        IDMap[l.ID] = l;
+        if(l.NextSiblingID!=-1) nextMap[l.NextSiblingID] = l;
+    }
+    for(let t of lists){
+        if(!nextMap[t.ID]){ //如果在下一节点映射没找到,则是第一个节点
+            firstNode = t;
+            break;
+        }
+    }
+    if(firstNode){
+        newList.push(firstNode);
+        delete IDMap[firstNode.ID];
+        setNext(firstNode,newList);
+    }
+    //容错处理,如果链断了的情况,直接添加到后面
+    for(let key in IDMap){
+        if(IDMap[key]) newList.push(IDMap[key])
+    }
+    return newList;
+
+    function setNext(node,array) {
+        if(node.NextSiblingID != -1){
+            let next = IDMap[node.NextSiblingID];
+            if(next){
+                array.push(next);
+                delete IDMap[next.ID];
+                setNext(next,array);
+            }
+        }
+    }
+
+}
+
+async  function getSEIProjects(projectID) {
+    let project = await  projectsModel.findOne({ID:projectID});
+    if(!project) throw new Error(`找不到建设项目:${projectID}`);
+    let tem_e = await projectsModel.find({ParentID:project.ID});
+    let engineers = [];
+    for(let e of tem_e){
+        if(!e.deleteInfo || !e.deleteInfo.deleted){
+            let tenders =  await projectsModel.find({ParentID:e.ID});
+            let children = [];
+            for(let t of tenders){
+                if(!t.deleteInfo || !t.deleteInfo.deleted){
+                    children.push(t);
+                }
+            }
+            e._doc.children = children;
+            engineers.push(e);
+        }
+    }
+    engineers = sortChildren(engineers);
+    project._doc.children = engineers;
+    return project;
+}
+
+async function loadSEIProjectData(projectID) {
+    let gljListModel = new GLJListModel();
+    let [gljList, mixRatioConnectData,mixRatioMap,unitPriceMap] = await gljListModel.getListByProjectId(projectID);
+    let rations = await ration_model.getDataSync(projectID);
+    let bills = await bill_model.getDataSync(projectID);
+    let ration_gljs = await  ration_glj_model.find({projectID:projectID});
+    let projectGLJs = {
+        gljList : gljList,
+        mixRatioConnectData:mixRatioConnectData,
+        mixRatioMap:mixRatioMap,
+        unitPriceMap:unitPriceMap
+    };
+    return{bills:bills,rations:rations,ration_gljs:ration_gljs,projectGLJs:projectGLJs}
+}
+
+async function setSEILibData(property){
+    if(property.engineerInfoLibID){//工程信息指标
+        let engineerInfo = await engineerInfoLib.findOne({'ID':property.engineerInfoLibID});
+        if(engineerInfo) property.engineerInfos = engineerInfo.info;
+    }
+    if(property.engineerFeatureLibID){//工程特征指标
+        let engineerFeature = await engineerFeatureLib.findOne({'ID':property.engineerFeatureLibID});
+        if(engineerFeature) property.engineerFeatures = engineerFeature.features;
+    }
+    if(property.materialLibID){//主要工料指标
+        let material = await materialLib.findOne({'ID':property.materialLibID});
+        if(material) property.materials = material.materials;
+    }
+    if(property.mainQuantityLibID){//主要工程量指标
+        let mainQuantity = await mainQuantityLib.findOne({'ID':property.mainQuantityLibID});
+        if(mainQuantity) property.mainQuantities = mainQuantity.index;
+    }
+    if(property.economicLibID){//主要工程量指标
+        let economic = await economicLib.findOne({'ID':property.economicLibID});
+        if(economic) property.economics = economic.index;
+    }
 }

+ 3 - 0
modules/main/facade/ration_facade.js

@@ -456,6 +456,9 @@ async function addRationGLJ(std,newRation,compilation) {
                 newGLJ.adjCoe = std_glj.adjCoe;
                 newGLJ.materialType = std_glj.materialType;
                 newGLJ.materialCoe = std_glj.materialCoe;
+                newGLJ.materialIndexType = std_glj.materialIndexType;
+                newGLJ.materialIndexUnit = std_glj.materialIndexUnit;
+                newGLJ.materialIndexCoe = std_glj.materialIndexCoe;
                 newGLJ.createType = 'normal';
                 let info =  await ration_glj_facade.getInfoFromProjectGLJ(newGLJ,unitPriceFileId,ext);
                 newGLJ = ration_glj_facade.createNewRecord(info);

+ 9 - 3
modules/main/models/bills.js

@@ -27,13 +27,16 @@ const billType ={
     BX:5//补项
 };
 
+
 class billsModel extends baseModel {
     constructor () {
         super(bills);
     };
-
-    getData (projectID, callback) {
-        this.model.find({'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
+    getQuery(projectID){
+        return {'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}
+    }
+     getData (projectID, callback) {
+        this.model.find(this.getQuery(projectID), '-_id', function(err, datas){
             if (!err) {
                 callback(0, projectConsts.BILLS, datas);
             } else {
@@ -41,6 +44,9 @@ class billsModel extends baseModel {
             };
         });
     };
+    async getDataSync(projectID){
+        return await this.model.find(this.getQuery(projectID),'-_id');
+    }
 
     save (user_id, datas, callback) {
         let functions = [];

+ 7 - 3
modules/main/models/ration.js

@@ -16,9 +16,11 @@ class rationModel extends baseModel {
     constructor () {
         super(ration);
     }
-
+    getQuery(projectID){
+        return {'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}
+    }
     getData (projectID, callback) {
-        ration.find({'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
+        ration.find(this.getQuery(projectID), '-_id', function(err, datas){
             if (!err) {
                 callback(0, projectConsts.RATION, datas);
             } else {
@@ -26,7 +28,9 @@ class rationModel extends baseModel {
             }
         });
     };
-
+    async getDataSync(projectID){
+        return await  ration.find(this.getQuery(projectID), '-_id');
+    }
     save (user_id, datas, callback) {
         let functions = [];
         let data;

+ 8 - 1
modules/main/routes/main_route.js

@@ -5,6 +5,7 @@
 
 import BaseController from "../../common/base/base_controller";
 const projectModel = require("../../pm/models/project_model");
+const pmFacade = require('../../pm/facade/pm_facade');
 let config = require("../../../config/config.js");
 module.exports =function (app) {
     const baseController = new BaseController();
@@ -22,6 +23,11 @@ module.exports =function (app) {
                     //允许协作的项目允许编辑,非只读
                     projectReadOnly = !projectCooperate;
                 }
+                let fileKind = '1'; //默认投标文件
+                let constructProject = await pmFacade.getConstructionProject(req.query.project);
+                if (constructProject && constructProject.property && constructProject.property.fileKind) {
+                    fileKind = constructProject.property.fileKind;
+                }
                 res.render('building_saas/main/html/main.html',
                     {
                         userAccount: req.session.userAccount,
@@ -32,7 +38,8 @@ module.exports =function (app) {
                         projectReadOnly: projectReadOnly,
                         projectCooperate: projectCooperate,
                         LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
-                        overWriteUrl:req.session.sessionCompilation.overWriteUrl
+                        overWriteUrl:req.session.sessionCompilation.overWriteUrl,
+                        fileKind: fileKind
                     });
             } else {
                 res.redirect('/pm');

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

@@ -15,7 +15,8 @@ module.exports = function (app) {
     projectRouter.post('/calcInstallationFee', projectController.calcInstallationFee);
     projectRouter.post('/saveProperty', projectController.saveProperty);
     projectRouter.post('/getDefaultColSetting', projectController.getDefaultColSetting);
-
+    projectRouter.post('/getSEIProjects', projectController.getSEIProjects);
+    projectRouter.post('/loadSEIProjectData', projectController.loadSEIProjectData);
     app.use('/project',projectRouter);
 };
 

+ 50 - 4
modules/pm/controllers/pm_controller.js

@@ -29,7 +29,8 @@ import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeMod
 let sectionTreeDao = new SectionTreeDao();
 let consts = require('../../main/models/project_consts');
 const rationLibModel = mongoose.model('std_ration_lib_map');
-
+const multiparty = require("multiparty");
+let logger = require("../../../logs/log_helper").logger;
 //统一回调函数
 let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
@@ -137,14 +138,14 @@ module.exports = {
         };
 
         // 清单:每文档doc只存储一条清单,每条清单都必须定位一次文档,无法合并处理
-        if (datas.bills.length > 0){
+        if (datas.bills && datas.bills.length > 0){
             for (let bill of datas.bills){
                 functions.push(updateFunc(billsModel, {projectID: datas.projectID, ID: bill.ID, deleteInfo: null}, bill));
             };
         };
 
         // 定额:每文档doc只存储一条定额,每条定额都必须定位一次文档,无法合并处理
-        if (datas.rations.length > 0){
+        if (datas.rations&& datas.rations.length > 0){
             for (let ration of datas.rations){
                 functions.push(updateFunc(rationsModel, {projectID: datas.projectID, ID: ration.ID, deleteInfo: null}, ration));
             };
@@ -320,6 +321,7 @@ module.exports = {
         rationValuation = await engineeringLibModel.getLib(rationValuation);
         let absoluteUrl = compilationData.overWriteUrl ? request.app.locals.rootDir + compilationData.overWriteUrl : request.app.locals.rootDir;
         let overWriteUrl = fs.existsSync(absoluteUrl) && fs.statSync(absoluteUrl).isFile()? compilationData.overWriteUrl : null;
+        let valuationOpts = billValuation.map(data => {return {name: data.name, id: data.id}});
         let renderData = {
             isFirst: isFirst,
             userAccount: request.session.userAccount,
@@ -327,6 +329,7 @@ module.exports = {
             compilationData: JSON.stringify(sessionCompilation),
             overWriteUrl: overWriteUrl,
             billValuation: JSON.stringify(billValuation),
+            valuationOpts: valuationOpts,
             rationValuation: JSON.stringify(rationValuation),
             engineeringList: JSON.stringify(engineering.List),
             compilationName: sessionCompilation.name,
@@ -712,7 +715,8 @@ module.exports = {
     },
     getBasicInfo: async function(req, res) {
         try {
-            let infoLib = await pm_facade.getBasicInfo(req.session.sessionCompilation._id);
+            let data = JSON.parse(req.body.data);
+            let infoLib = await pm_facade.getBasicInfo(req.session.sessionCompilation._id, data.fileKind);
             callback(req, res, 0, 'success', infoLib ? infoLib.info : []);
         } catch (err) {
             console.log(err);
@@ -746,5 +750,47 @@ module.exports = {
         } catch (err) {
             callback(req, res, 1, err, null);
         }
+    },
+    getProjectPlaceholder: async function(req, res) {
+        let data = JSON.parse(req.body.data);
+        try {
+            let countRst = await pm_facade.getProjectPlaceholder(data);
+            callback(req, res, 0, 'succes', countRst);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    },
+    importInterface: async function(req, res) {
+        logger.info(`${req.ip} importInterface`);
+        const uploadOption = {
+            uploadDir: './public'
+        };
+        let uploadFullName = '';
+        const form = new multiparty.Form(uploadOption);
+        form.parse(req, async function(err, fields, files) {
+            try {
+                let file = files.file && files.file.length ? files.file[0] : null;
+                if (!file) {
+                    throw '无有效数据';
+                }
+                uploadFullName = file.path;
+                //获取源数据
+                let srcStr = fs.readFileSync(file.path, 'utf8');
+                if (!srcStr) {
+                    throw '无有效数据'
+                }
+                let importData = JSON.parse(srcStr);
+                fs.unlinkSync(file.path);
+                let projectData = await pm_facade.importProject(importData, req.session.sessionUser.id, req.session.sessionCompilation._id);
+                callback(req, res, 0, '', projectData);
+            } catch (err) {
+                console.log(err);
+                if(uploadFullName && fs.existsSync(uploadFullName)){
+                    fs.unlinkSync(uploadFullName);
+                }
+                callback(req, res, 1, err, null);
+            }
+        });
     }
 };

+ 370 - 5
modules/pm/facade/pm_facade.js

@@ -26,7 +26,9 @@ module.exports={
     changeFile:changeFile,
     getBasicInfo: getBasicInfo,
     getProjectFeature: getProjectFeature,
-    getProjectByGranularity: getProjectByGranularity
+    getProjectByGranularity: getProjectByGranularity,
+    importProject: importProject,
+    getProjectPlaceholder: getProjectPlaceholder
 };
 
 
@@ -64,6 +66,9 @@ let engineeringModel = mongoose.model('engineering_lib');
 let basicInfoModel = mongoose.model('std_basic_info_lib');
 let projectFeatureModel = mongoose.model('std_project_feature_lib');
 let productModel = mongoose.model('product');
+let stdRationItemModel = mongoose.model('std_ration_lib_ration_items');
+let stdGljItemModel = mongoose.model('std_glj_lib_gljList');
+import BillsTemplateModel from "../models/templates/bills_template_model";
 
 let featureLibModel =  mongoose.model("std_project_feature_lib");
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
@@ -74,8 +79,19 @@ import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment';
 import billsFlags from '../../common/const/bills_fixed';
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
-
-
+import {
+    defaultDecimal,
+    billsQuantityDecimal,
+    displaySetting,
+    calcOptions,
+    tenderSetting,
+    G_FILE_VER
+} from '../models/project_property_template';
+let labourCoeFacade = require('../../main/facade/labour_coe_facade');
+let calcProgramFacade = require('../../main/facade/calc_program_facade');
+let mainColLibModel = mongoose.model('std_main_col_lib');
+import EngineeringLibModel from "../../users/models/engineering_lib_model";
+let installationFacade = require('../../main/facade/installation_facade');
 
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
@@ -1054,7 +1070,8 @@ async function changeFile(datas,userID,fileID,name,from,type){//from 费率或
 
 }
 
-async function getBasicInfo(compilationID) {
+//获取费用定额绑定的基本信息库数据
+async function getBasicInfo(compilationID, fileKind = null) {
     let compilation = await compilationModel.findOne({_id: mongoose.Types.ObjectId(compilationID)});
     if (!compilation) {
         return null;
@@ -1073,6 +1090,20 @@ async function getBasicInfo(compilationID) {
         return null;
     }
     let infoLib = await basicInfoModel.findOne({ID: engineering.info_lib[0].id});
+    //提取文件类型中需要的数据 (投标项目可能不需要招标的一些信息)
+    if (fileKind && infoLib && infoLib.info && infoLib.info.length) {
+        let strMap = {
+            1: 'tender',    //投标
+            2: 'bid',       //招标
+            3: 'control'    //控制价
+        };
+        let needfulData = infoLib.info.filter(data => !data.fileKind || data.fileKind === strMap[fileKind]);
+        needfulData.forEach(nData => {
+            let needfulSub = nData.items.filter(sData => !sData.fileKind || sData.fileKind === strMap[fileKind]);
+            nData.items = needfulSub;
+        });
+        infoLib.info = needfulData;
+    }
     return infoLib;
 }
 
@@ -1141,6 +1172,340 @@ async function getProjectByGranularity(tenderID, granularity, userID, versionNam
     let product = await productModel.findOne({});
     let company = product.company || '珠海纵横创新软件有限公司',
         version = product.version || '';
-    constructionProject._doc.softInfo = new Buffer(`${company};${versionName};${version};${userID}`).toString('base64');
+    constructionProject._doc.softInfo = `${company};${versionName};${version};${userID}`;
     return constructionProject;
+}
+
+//获取项目数据占位ID
+async function getProjectPlaceholder(data) {
+    let rst = {};
+    //项目本身数据
+    if (data.projectCount) {
+        let projectCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.project, data.projectCount);
+        rst.project = projectCount.sequence_value - data.projectCount + 1;
+    }
+    //项目人材机数据
+    if (data.projectGLJCount) {
+        let projectGLJCount =  await counter.counterDAO.getIDAfterCountSync(counter.moduleName.glj_list, data.projectGLJCount);
+        rst.projectGLJ = projectGLJCount.sequence_value - data.projectGLJCount + 1;
+    }
+    //组成物数据
+    if (data.ratioCount) {
+        let ratioCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.mix_ratio, data.ratioCount);
+        rst.ratio = ratioCount.sequence_value - data.ratioCount + 1;
+    }
+    //单价文件数据
+    if (data.unitPriceFileCount) {
+        let unitPriceFileCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.unit_price_file, data.unitPriceFileCount);
+        rst.unitPriceFile = unitPriceFileCount.sequence_value - data.unitPriceFileCount + 1;
+    }
+    //单价数据
+    if (data.unitPriceCount) {
+        let unitPriceCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.unit_price, data.unitPriceCount);
+        rst.unitPrice = unitPriceCount.sequence_value - data.unitPriceCount + 1;
+    }
+    return rst;
+}
+
+/*
+* 项目详细数据都导入完成了,再生成项目数据(项目管理界面数据)
+* */
+async function importProject(importObj, userID, compilationID) {
+    let toInsertProjects = [importObj];  //待新增项目数据
+    await setupProject(importObj);
+    //设置项目ID及相关数据
+    for (let curEng of importObj.engs) {
+        await setupProject(curEng);
+        toInsertProjects.push(curEng);
+        for (let curTender of curEng.tenders) {
+            await setupProject(curTender.tender);
+            //插入单位工程的详细数据
+            await importTenderDetail(curTender);
+            toInsertProjects.push(curTender.tender);
+        }
+        delete curEng.tenders;
+    }
+    delete importObj.engs;
+    //项目内部数据设置、新增完毕后,插入项目本身的数据,更新前节点数据
+    let bulks = [];
+    //如果有前节点,更新前节点
+    if (importObj.preID !== -1) {
+        bulks.push({
+            updateOne: {filter: {ID: importObj.preID}, update: {$set: {NextSiblingID: importObj.ID}}}
+        });
+    }
+    for (let insertP of toInsertProjects) {
+        bulks.push({
+            insertOne: {document: insertP}
+        });
+    }
+    if (bulks.length > 0) {
+        await projectModel.bulkWrite(bulks);
+    }
+    let summaryInfo = await getSummaryInfo([importObj.ID]);
+    //设置汇总字段
+    for(let proj of toInsertProjects){
+        let summaryProj = summaryInfo[proj.ID];
+        if(summaryProj){
+            proj.engineeringCost = summaryProj.engineeringCost;
+            proj.subEngineering = summaryProj.subEngineering;
+            proj.measure = summaryProj.measure;
+            proj.safetyConstruction = summaryProj.safetyConstruction;
+            proj.other = summaryProj.other;
+            proj.charge = summaryProj.charge;
+            proj.tax = summaryProj.tax;
+            proj.rate = summaryProj.rate;
+            proj.buildingArea = summaryProj.buildingArea;
+            proj.perCost = summaryProj.perCost;
+        }
+    }
+    return toInsertProjects;
+
+
+    //给项目数据设置一些需要的数据
+    async function setupProject(data) {
+        data.userID = userID;
+        data.compilation = compilationID;
+        data.fileVer = G_FILE_VER;
+        data.createDateTime = new Date();
+        if (data.projType === 'Project') {
+            await setupConstruct(data);
+        } else if (data.projType === 'Tender') {
+            await setupTender(data);
+        }
+    }
+    //给建设项目设置一些数据
+    async function setupConstruct(data) {
+        //更新基本信息, 按照key匹配
+        let infoLib = await getBasicInfo(data.compilation, data.property.fileKind);
+        if (infoLib) {
+            //标准基本信息库的数据打平
+            let flatDatas = [];
+            infoLib.info.forEach(ifData => flatDatas.push(...ifData.items));
+            data.basicInformation.forEach(importI => {
+                flatDatas.forEach(item => {
+                    if (item.key === 'engineeringName') {
+                        item.value = data.name;
+                    } else if (item.key === 'fileKind') {
+                        item.value = {'1': '投标', '2': '招标'}[data.property.fileKind]
+                    } else if (item.key === 'taxModel') {
+                        item.value = {'1': '一般计税法', '2': '简易计税法'}[data.property.taxType]
+                    }
+                    if (item.key === importI.key) {
+                        item.value = importI.value;
+                    }
+                });
+            });
+        }
+        data.property.basicInformation = infoLib ? infoLib.info : [];
+    }
+    //给单位工程设置一些数据
+    async function setupTender(data) {
+        //小数位数
+        data.property.decimal = defaultDecimal;
+        //清单工程量精度
+        data.property.billsQuantityDecimal = billsQuantityDecimal;
+        //呈现选项
+        data.property.displaySetting = displaySetting;
+
+        data.property.billsCalcMode = 0;
+        data.property.zanguCalcMode = 0;
+        //计算选项
+        data.property.calcOptions = calcOptions;
+        //安装增加费
+        if(data.property.isInstall === true || data.property.isInstall === 'true'){//判断是否安装工程
+            await installationFacade.copyInstallationFeeFromLib(data.ID, data.property.engineering_id);
+        }
+        //锁定清单
+        data.property.lockBills = false;
+        //工料机单价调整系数
+        data.property.tenderSetting = tenderSetting;
+        //工程特征相关更新
+        let featureLib = await getProjectFeature(data.property.valuation, data.property.engineeringName, data.property.feeStandardName);
+        if (featureLib) {
+            //把导入的数据设置到默认生成的数据中,按名称匹配 (导入项不确定,因此无法确定获取项的key)
+            data.projectFeature.forEach(importF => {
+                let matchData = featureLib.feature.find(f => f.dispName === importF.name);
+                if (matchData) {
+                    matchData.value = importF.value;
+                }
+            });
+            //设置工程专业的值为费用标准的值..
+            featureLib.feature.forEach(f => {
+                if (f.key === 'engineering') {
+                    f.value = data.property.feeStandardName;
+                }
+            });
+        }
+        data.property.projectFeature = featureLib ? featureLib.feature : [];
+    }
+}
+
+//插入单位工程内部详细数据
+async function importTenderDetail(tenderData) {
+    //单价文件
+    let upFile = {
+        id: tenderData.tender.property.unitPriceFile.id,
+        name: tenderData.tender.name,
+        project_id: tenderData.tender.ID,
+        user_id: tenderData.tender.userID,
+        root_project_id: tenderData.tender.property.rootProjectID
+    };
+    await unitPriceFileModel.create(upFile);
+    //费率文件
+    let feeRateFileID = await feeRate_facade.newFeeRateFile(tenderData.tender.userID, tenderData.tender);
+    tenderData.tender.property.feeFile = feeRateFileID ? feeRateFileID : -1;
+    //人工系数文件
+    let lcFile = await labourCoeFacade.newProjectLabourCoe(tenderData.tender);
+    tenderData.tender.property.labourCoeFile = lcFile ? lcFile : null;
+    let cpFile = await calcProgramFacade.newProjectCalcProgramFile(tenderData.tender);
+    tenderData.tender.property.calcProgramFile = cpFile ? cpFile : null;
+    //列设置
+    let engineeringModel = new EngineeringLibModel();
+    let engineering = await engineeringModel.getEngineering(tenderData.tender.property.engineering_id);
+    let mainTreeCol = await mainColLibModel.findOne({ID: tenderData.tender.property.colLibID});
+    await projectSettingModel.create({projectID: tenderData.tender.ID, main_tree_col: mainTreeCol.main_tree_col, glj_col: engineering.glj_col});
+    //清单
+    if (tenderData.bills.length) {
+        await billsModel.insertMany(tenderData.bills);
+    }
+    //投标文件中,才会有下面这些数据
+    if (enterDetail(tenderData)) {
+        //匹配标准数据,更新一些标准数据
+        await setupStdData(tenderData);
+        let task = [];
+        //定额
+        if (tenderData.ration.length) {
+            task.push(rationModel.insertMany(tenderData.ration))
+        }
+        //定额人材机
+        if (tenderData.rationGLJ.length) {
+            task.push(rationGLJModel.insertMany(tenderData.rationGLJ));
+        }
+        //定额调整系数
+        if (tenderData.rationCoe.length) {
+            task.push(rationCoeModel.insertMany(tenderData.rationCoe));
+        }
+        //项目人材机
+        if (tenderData.projectGLJ.length) {
+            task.push(gljListModel.insertMany(tenderData.projectGLJ));
+        }
+        //组成物
+        if (tenderData.mixRatio.length) {
+            task.push(mixRatioModel.insertMany(tenderData.mixRatio));
+        }
+        //单价文件
+        if (tenderData.unitPrice.length) {
+            task.push(unitPriceModel.insertMany(tenderData.unitPrice));
+        }
+        await Promise.all(task);
+    }
+    //继续处理定额等数据
+    function enterDetail(tenderData) {
+        return tenderData.ration.length ||
+            tenderData.rationGLJ.length ||
+            tenderData.projectGLJ.length ||
+            tenderData.mixRatio.length ||
+            tenderData.unitPrice.length;
+    }
+}
+//匹配标准数据,需要匹配标准定额,更新导入的定额人材机的定额消耗量等数据
+async function setupStdData(tenderData) {
+    //获取标准定额数据 (定额子目的编码查找)
+    let matchRationCodes = [...new Set(tenderData.ration.map(ration => ration.code))];
+    if (!matchRationCodes.length) {
+        return;
+    }
+    //限制在当前费用定额可用的定额库里查找
+    let stdRations = await stdRationItemModel.find({code: {$in: matchRationCodes}, rationRepId: {$in: tenderData.tender.rationLibIDs}},
+                                                    '-_id -rationAssList -rationCoeList -rationInstList');
+    //标准定额code - 映射
+    let stdRationCodeMap = {};
+    stdRations.forEach(stdRation => stdRationCodeMap[stdRation.code] = stdRation);
+    //获取标准人材机数据 (人材机汇总的编码查找)
+    let matchGLJCodes = [...new Set(tenderData.projectGLJ.map(pGLJ => pGLJ.original_code))];
+    if (!matchGLJCodes.length) {
+        return;
+    }
+    //限制在当前费用定额可用的人材机库里查找
+    let stdGLJs = await stdGljItemModel.find({code: {$in: matchGLJCodes}, repositoryId: {$in: tenderData.tender.gljLibIDs}},
+                                             '-_id -component -priceProperty');
+    //标准人材机code - 映射
+    let stdGLJCodeMap = {};
+    stdGLJs.forEach(stdGLJ => stdGLJCodeMap[stdGLJ.code] = stdGLJ);
+    //更新定额数据
+    tenderData.ration.forEach(r => {
+        let stdRation = stdRationCodeMap[r.code];
+        if (stdRation) {
+            r.caption = stdRation.caption;
+            r.from = 'std';
+            r.libID = stdRation.rationRepId;
+            r.stdID = stdRation.ID;
+            r.prefix = stdRation.rationRepId == tenderData.tender.defaultRationLib ? '' : '借';
+            r.content = stdRation.jobContent;
+            if (stdRation.feeType) {
+                r.programID = stdRation.feeType;
+            }
+        } else {
+            r.from = 'cpt';
+            r.prefix = '补';
+        }
+    });
+    //更新定额人材机数据
+    tenderData.rationGLJ.forEach(rGLJ => {
+        rGLJ.from = 'cpt';
+        //匹配定额
+        let stdRation = stdRationCodeMap[rGLJ.rationCode];
+        if (stdRation) {
+            //根据导入数据的定额人材机编码匹配人材机
+            let stdGLJ = stdGLJCodeMap[rGLJ.original_code];
+            if (stdGLJ) {
+                rGLJ.from = 'std';
+                rGLJ.GLJID = stdGLJ.ID;
+                rGLJ.type = stdGLJ.gljType;
+                rGLJ.shortName = stdGLJ.shortName;
+                rGLJ.repositoryId = stdGLJ.repositoryId;
+                rGLJ.model = stdGLJ.model;
+                rGLJ.adjCoe = stdGLJ.adjCoe;
+                //找匹配到的标准定额中定额人材机的相应人材机,更新定额消耗
+                let stdRationGLJ = stdRation.rationGljList.find(data => data.gljId === stdGLJ.ID);
+                if (stdRationGLJ) {
+                    rGLJ.rationItemQuantity = stdRationGLJ.consumeAmt;
+                }
+            }
+        }
+    });
+    //更新人材机汇总数据
+    tenderData.projectGLJ.forEach(pGLJ => {
+        let stdGLJ = stdGLJCodeMap[pGLJ.original_code];
+        if (stdGLJ) {
+            pGLJ.glj_id = stdGLJ.ID;
+            pGLJ.model = stdGLJ.model;
+            if (pGLJ.type !== stdGLJ.gljType) { //更新组成物connect_key
+                let keyStr = [pGLJ.code || 'null', pGLJ.name || 'null', pGLJ.specs || 'null', pGLJ.unit || 'null', pGLJ.type].join('|-|');
+                let ratios = tenderData.mixRatio.filter(ratio =>
+                    ratio.connect_key === keyStr);
+                let newKeyStr = [pGLJ.code || 'null', pGLJ.name || 'null', pGLJ.specs || 'null', pGLJ.unit || 'null', stdGLJ.gljType || 'null'].join('|-|');
+                ratios.forEach(ratio => ratio.connect_key = newKeyStr);
+            }
+            pGLJ.type = stdGLJ.gljType;  //更新类型,标准的数据类型更准确,导入的类型数据有细分识别不了
+        }
+    });
+    //更新单价文件数据
+    tenderData.unitPrice.forEach(up => {
+        let stdGLJ = stdGLJCodeMap[up.original_code];
+        if (stdGLJ) {
+            up.glj_id = stdGLJ.ID;
+            up.type = stdGLJ.gljType;
+            up.short_name = stdGLJ.shortName;
+        }
+    });
+    //更新组成物数据
+    tenderData.mixRatio.forEach(ratio => {
+        let stdGLJ = stdGLJCodeMap[ratio.code];
+        if (stdGLJ) {
+            ratio.glj_id = stdGLJ.ID;
+            ratio.type = stdGLJ.gljType;
+        }
+    });
 }

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

@@ -28,7 +28,8 @@ import {
     projectFeature,
     displaySetting,
     calcOptions,
-    tenderSetting
+    tenderSetting,
+    G_FILE_VER
 } from './project_property_template';
 import optionSetting from '../../options/models/optionTypes';
 import fixedFlag from '../../common/const/bills_fixed';
@@ -41,6 +42,8 @@ let feeRateFacade = require('../../fee_rates/facade/fee_rates_facade');
 let labourCoeFacade = require('../../main/facade/labour_coe_facade');
 let calcProgramFacade = require('../../main/facade/calc_program_facade');
 let installationFacade = require('../../main/facade/installation_facade');
+let projectFacade = require('../../main/facade/project_facade');
+
 let pmFacade = require('../facade/pm_facade');
 let logger = require("../../../logs/log_helper").logger;
 let BillsModel = require("../../main/models/bills").model;
@@ -54,7 +57,7 @@ let optionModel = mongoose.model('options');
 function ProjectsDAO() {
 }
 
-let G_FILE_VER = '1.0.1';
+//let G_FILE_VER = '1.0.1';
 
 ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, callback) {
     try {//
@@ -147,7 +150,6 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     Object.keys(data.updateData.property.unitPriceFile).length > 0 &&
                     data.updateData.property.unitPriceFile.id === '') {
                     let unitPriceFileModel = new UnitPriceFileModel();
-
                     let insertData = {
                         name: data.updateData.name,
                         project_id: data.updateData.ID,
@@ -183,15 +185,24 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.lockBills = false;
                     //工料机单价调整系数
                     data.updateData.property.tenderSetting = tenderSetting;
-                }
-
+                     //添加重庆经济指标数据
+                    await projectFacade.setSEILibData(data.updateData.property);
+                }else if (data.updateData.projType === projectType.project) {
+                    //更新基本信息
+                    data.updateData.property.basicInformation.forEach(function (pData) {
+                        pData.items.forEach(function (item) {
+                            if (item.key === 'engineeringName') {
+                                item.value = data.updateData.name;
+                            } else if (item.key === 'fileKind') {
+                                item.value = {'1': '投标', '2': '招标'}[data.updateData.property.fileKind]
+                            } else if (item.key === 'taxModel') {
+                                item.value = {'1': '一般计税法', '2': '简易计税法'}[data.updateData.property.taxType]
+                            }
+                        });
+                    });
+                }                
                 newProject = new Projects(data.updateData);
-               /* // 查找同级是否存在同名数据
-                let exist = await this.isExist(userId, compilationId, data.updateData.name, data.updateData.ParentID);
-                if (exist) {
-                    callback(1, '同级目录已存在相同名称数据.', null);
-                    return;
-                }*/
+
                 if (data.updateData.projType === 'Tender') {
                     let feeRateFileID = await feeRateFacade.newFeeRateFile(userId, data.updateData);
                     newProject.property.feeFile = feeRateFileID ? feeRateFileID : -1;
@@ -297,6 +308,11 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
     }
 };
 
+//导入接口数据
+ProjectsDAO.prototype.importInterface = async function (srcData) {
+
+};
+
 ProjectsDAO.prototype.udpateUserFiles = async function (userId, datas, callback) {
     let updateType = {update: 'update', delete: 'delete'};
     let deleteInfo = Object.create(null);
@@ -387,13 +403,23 @@ ProjectsDAO.prototype.rename = async function (userId, compilationId, data, call
             throw '请填写名称!';
         }
         data.newName = data.newName.trim();
-        //重名前端控制
-       /* // 查找同级是否存在同名数据
-        let exist = await this.isExist(userId, compilationId, data.newName, data.parentID);
-        if (exist) {
-            throw '同级目录已存在相同名称数据';
-        }*/
-
+        let project = await Projects.findOne({ID: data.id});
+        if (!project) {
+            throw '项目不存在';
+        }
+        if (project.projType === 'Project' && project.property && Array.isArray(project.property.basicInformation)) {
+            //更新基本信息
+            project.property.basicInformation.forEach(function (pData) {
+                pData.items.forEach(function (item) {
+                    if (item.key === 'engineeringName') {
+                        item.value = data.newName;
+                    }
+                });
+            });
+            await Projects.update({ID: data.id}, {$set: {name: data.newName, 'property.basicInformation': project.property.basicInformation}});
+        } else {
+            await Projects.update({ID: data.id}, {$set: {name: data.newName}});
+        }
         Projects.update({userID: userId, ID: data.id}, {name: data.newName}, function (err) {
             if (err) {
                 throw '项目不存在';
@@ -813,6 +839,7 @@ ProjectsDAO.prototype.getConstructionProperty = async function (projectID) {
     return constructionProject.property;
 };
 
+//获取建设项目的基本信息
 ProjectsDAO.prototype.getBasicInfo = async function (projectID) {
     //获取建设项目
     let constructionProject = await pmFacade.getConstructionProject(projectID);

+ 3 - 1
modules/pm/models/project_property_template.js

@@ -138,4 +138,6 @@ const projectFeature = [
     {dispName: '门窗材料及装饰', key: 'doorsWindowsMaterial', value: ''}
 ];
 
-export {defaultDecimal, billsQuantityDecimal, basicInformation, projectFeature,displaySetting,calcOptions,tenderSetting};
+let G_FILE_VER = '1.0.1';
+
+export {defaultDecimal, billsQuantityDecimal, basicInformation, projectFeature,displaySetting,calcOptions,tenderSetting, G_FILE_VER};

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

@@ -64,7 +64,13 @@ module.exports = function (app) {
     pmRouter.post('/getBasicInfo', pmController.getBasicInfo);
     pmRouter.post('/getProjectFeature', pmController.getProjectFeature);
     pmRouter.post('/getProjectByGranularity', pmController.getProjectByGranularity);
+
     app.use('/pm/api', pmRouter);
+
+    let importRouter = express.Router();
+    importRouter.post('/getProjectPlaceholder', pmController.getProjectPlaceholder);
+    importRouter.post('/importInterface', pmController.importInterface);
+    app.use('/pm/import', importRouter);
 };
 
 

+ 3 - 0
modules/ration_glj/facade/ration_glj_facade.js

@@ -596,6 +596,9 @@ function getGLJSearchInfo(ration_glj) {
         adjCoe: ration_glj.adjCoe,
         materialType:ration_glj.materialType,
         materialCoe:ration_glj.materialCoe,
+        materialIndexType:ration_glj.materialIndexType,
+        materialIndexUnit:ration_glj.materialIndexUnit,
+        materialIndexCoe:ration_glj.materialIndexCoe,
         from: ration_glj.from ? ration_glj.from : 'std'//std:标准工料机库, cpt:补充工料机库
     };
     let glj_type_object = glj_type_util.getStdGljTypeCacheObj();

+ 10 - 0
modules/templates/controllers/bills_template_controller.js

@@ -33,5 +33,15 @@ module.exports = {
         BillsTemplateData.getNewBillsTemplateID(data.count, function (err, message, data) {
             callback(req, res, err, message, data);
         });
+    },
+    getNeedfulTemplate: async function (req, res) {
+        let data = JSON.parse(req.body.data);
+        try {
+            let needfulDatas = await BillsTemplateData.getNeedfulTemplate(data.templateLibID);
+            callback(req, res, 0, 'succes', needfulDatas);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
     }
 }

+ 88 - 0
modules/templates/models/bills_template.js

@@ -6,6 +6,8 @@ let counter = require("../../../public/counter/counter.js");
 let mongoose = require('mongoose');
 let BillsTemplates = mongoose.model('temp_bills');
 let BillsTemplateDAO = function(){};
+import BillsTemplateModel from "../../pm/models/templates/bills_template_model";
+const uuidV1 = require('uuid/v1');
 
 BillsTemplateDAO.prototype.getTemplate = function (type, callback) {
     if (callback) {
@@ -68,4 +70,90 @@ BillsTemplateDAO.prototype.getNewBillsTemplateID = function (count, callback) {
     });
 }
 
+//过滤掉非必要清单的清单模板
+BillsTemplateDAO.prototype.getNeedfulTemplate = async function (templateLibID) {
+    let billsTemplateModel = new BillsTemplateModel();
+    let templateData = await billsTemplateModel.getTemplateDataForNewProj(templateLibID);
+    let billsDatas = JSON.parse(JSON.stringify(templateData));
+    //设置同层序号,为了后续过滤掉非必要模板数据、插入接口清单数据后,能生成正确的顺序的树
+    setSeqByNext(billsDatas);
+    function getFlag(data) {
+        return data.flags && data.flags[0] && data.flags[0].flag || '';
+    }
+    //过滤掉不含清单固定类别的模板数据 (导入接口只包含必要的清单模板数据)
+    let needfulDatas = billsDatas.filter(data => getFlag(data));
+    sortToTreeData(needfulDatas);
+    return needfulDatas;
+};
+
+/*
+ * 将同层的清单数据,按照树结构顺序设置序号
+ * @param {Array} billsData(清单模板数据)
+ * */
+function setSeqByNext(billsData) {
+    //获取同层数据
+    let sameDepthDatas = {};    //按照ParentID区分
+    for (let data of billsData) {
+        if (!sameDepthDatas[data.ParentID]) {
+            sameDepthDatas[data.ParentID] = [];
+        }
+        sameDepthDatas[data.ParentID].push(data);
+    }
+    //设置同层节点的序号
+    for (let sameDepth of Object.values(sameDepthDatas)) {
+        let sortedData = getDataBySorted(sameDepth),
+            seq = 1;
+        sortedData.forEach((data => data.seq = seq++));
+    }
+    //将每个同层的数据设置好序号
+    //获取根据树结构NextSibling排序的同层数据
+    function getDataBySorted(datas) {
+        //链断了返回空数组
+        let target = [];
+        let last = datas.find(data => data.NextSiblingID == -1);
+        while (last && target.length !== datas.length) {
+            target.push(last);
+            last = datas.find(data => data.NextSiblingID == last.ID);
+        }
+        //链断了即清单模板数据的树结构有问题,这里做下兼容:
+        // 1.数据没问题,返回排序过后的同层数据数组    2.数据有问题,返回不排序的同层数组
+        return target.length === datas.length ? target.reverse() : datas;
+    }
+}
+
+//根据同层序号,设置NextSiblingID
+function sortSeqToNextSibling(needfulData) {
+    let sameDepthDatas = {};    //按照ParentID区分
+    for (let data of needfulData) {
+        if (!sameDepthDatas[data.ParentID]) {
+            sameDepthDatas[data.ParentID] = [];
+        }
+        sameDepthDatas[data.ParentID].push(data);
+    }
+    for (let sameDepth of Object.values(sameDepthDatas)) {
+        sameDepth.sort((a, b) => a.seq - a.seq);
+        for (let i = 0; i < sameDepth.length; i++) {
+            let cur = sameDepth[i],
+                next = sameDepth[i + 1];
+            cur.NextSiblingID = next ? next.ID : -1;
+        }
+    }
+}
+
+//清单模板数据转换为uuID树结构数据
+function sortToTreeData(needfulData) {
+    sortSeqToNextSibling(needfulData);
+    let uuidMaping = {};
+    uuidMaping['-1'] = -1;
+    //建立uuid-ID映射
+    for(let bill of needfulData){
+        uuidMaping[bill.ID] = uuidV1();
+    }
+    needfulData.forEach(function (template) {
+        template.ID = uuidMaping[template.ID] ? uuidMaping[template.ID] : -1;
+        template.ParentID = uuidMaping[template.ParentID] ? uuidMaping[template.ParentID] : -1;
+        template.NextSiblingID = uuidMaping[template.NextSiblingID] ? uuidMaping[template.NextSiblingID] : -1;
+    });
+}
+
 module.exports = new BillsTemplateDAO();

+ 1 - 0
modules/templates/routes/bills_template_router.js

@@ -37,6 +37,7 @@ module.exports = function (app) {
     billsTemplateRouter.post('/getBillsTemplate', billsTemplateController.getBillsTemplate);
     billsTemplateRouter.post('/updateBillsTemplate', billsTemplateController.updateBillsTemplate);
     billsTemplateRouter.post('/getNewBillsTemplateID', billsTemplateController.getNewBillsTemplateID);
+    billsTemplateRouter.post('/getNeedfulTemplate', billsTemplateController.getNeedfulTemplate);
     app.use('/template/bills/api', billsTemplateRouter);
 }
 

+ 4 - 1
public/counter/counter.js

@@ -21,7 +21,10 @@ const COUNTER_MODULE_NAME = {
     billsLib: 'billsLib',
     coeList: 'coeList',
     complementaryCoeList: 'complementary_coe_list',
-    glj_list: 'glj_list'
+    glj_list: 'glj_list',
+    mix_ratio: 'mix_ratio',
+    unit_price_file: 'unit_price_file',
+    unit_price: 'unit_price'
 }
 /*const PROJECT_COUNTER = 'projects', USER_COUNTER = 'users', BILL_COUNTER = 'bills', RATION_COUNTER = 'rations',
     REPORT_COUNTER = 'rptTemplates', FEE_COUNTER = 'fees'*/

+ 2 - 2
public/gljUtil.js

@@ -28,8 +28,8 @@ function getGLJPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,i
     return gljNodeUtil.getGLJPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
 }
 
-function getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio=false) {
-    return gljNodeUtil.getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
+function getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio=false) {
+    return gljNodeUtil.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil);
 }
 
 function getBasePrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio=false) {

+ 56 - 0
public/web/PerfectLoad.js

@@ -85,3 +85,59 @@ jQuery.bootstrapLoading = {
         $("#loadingPage").remove();
     }
 }
+
+const SCComponent = (() => {
+    /*
+    * 假滚动条,0 - 80% 快, 80% - 95%很慢,95%开始停住,直到调用end方法
+    * */
+    const InitProgressBar = (() => {
+        function ProgressBar($modal = $('#progress'), $title = $('#progress-title'),
+                             $content = $('#progress-content'), $bar = $('#progressBar')) {
+            this.$modal = $modal;
+            this.$title = $title;
+            this.$content = $content;
+            this.$bar = $bar;
+        }
+        //显示滚动条,自动处理滚动条速度
+        ProgressBar.prototype.start = function (title, content) {
+            this.$title.text(title);
+            this.$content.text(content);
+            this.$bar.css('width', `0%`);
+            this.$modal.modal('show');
+            this.outer = setInterval(() => {
+                let curWidth = parseInt(this.$bar[0].style.width.replace('%', ''));
+                curWidth = parseInt(curWidth + 2);
+                this.$bar.css('width', `${curWidth}%`);
+                if (curWidth >= 80) {
+                    clearInterval(this.outer);
+                }
+            }, 100);
+            this.inner = setInterval(() => {
+                let curWidth = parseFloat(this.$bar[0].style.width.replace('%', ''));
+                if (curWidth >= 80) {
+                    curWidth = parseFloat(curWidth + 0.1);
+                    this.$bar.css('width', `${curWidth}%`);
+                    if (curWidth >= 95) {
+                        clearInterval(this.inner);
+                    }
+                }
+            }, 500);
+        };
+        //结束显示滚动条,滚动条从当前位置滚到100% 消失
+        ProgressBar.prototype.end = function () {
+            if (this.outer) {
+                clearInterval(this.outer);
+            }
+            if (this.inner) {
+                clearInterval(this.inner);
+            }
+            $('#progressBar').css('width', '100%');
+            setTimeout(() => {
+                this.$modal.modal('hide');
+            }, 500);
+        };
+        return ProgressBar;
+    })();
+
+    return {InitProgressBar}
+})();

+ 4 - 4
public/web/gljUtil.js

@@ -166,7 +166,7 @@ let gljUtil = {
     },
     getGLJPrice:function (glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil) {
         let result = {};
-        result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
+        result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil);
         if(this.calcPriceDiff(glj,calcOptions)==true){//计取价差
             result.basePrice = this.getBasePrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
             result.adjustPrice = this.getAdjustPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
@@ -176,7 +176,7 @@ let gljUtil = {
         }
         return result;
     },
-    getMarketPrice:function (glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil,tenderCoe) {
+    getMarketPrice:function (glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe) {
         let price_decimal = decimalObj.glj.unitPrice;
         let price_hasM_decimal = decimalObj.glj.unitPriceHasMix?decimalObj.glj.unitPriceHasMix:decimalObj.glj.unitPrice;
         let quantity_decimal = decimalObj.glj.quantity;
@@ -193,8 +193,8 @@ let gljUtil = {
                     'unit': ratio.unit
                 });
                 if(tem){
-                    let priceData=this.getGLJPrice(tem,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,true,_,scMathUtil);
-                    let temP = scMathUtil.roundForObj(priceData.marketPrice* priceCoe * scMathUtil.roundForObj(ratio.consumption,quantity_decimal),process_decimal);
+                    let tem_marketPrice = this.getMarketPrice(tem,projectGLJDatas,calcOptions,decimalObj,true,_,scMathUtil);  //let priceData=this.getGLJPrice(tem,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,true,_,scMathUtil);
+                    let temP = scMathUtil.roundForObj(tem_marketPrice * priceCoe * scMathUtil.roundForObj(ratio.consumption,quantity_decimal),process_decimal);
                     p = scMathUtil.roundForObj(temP + p,process_decimal);
                 }
             }

+ 139 - 6
public/web/sheet/sheet_common.js

@@ -109,6 +109,72 @@ var sheetCommonObj = {
             area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
         }
     },
+    showTreeData:function (sheet,setting,data) {
+        let ch = GC.Spread.Sheets.SheetArea.viewport;
+        let parentMap=_.groupBy(data, 'ParentID');
+        let visibleMap = {};
+        let styleRow=[];
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for (let col = 0; col < setting.header.length; col++) {
+            let hAlign = "left", vAlign = "center";
+            if (setting.header[col].hAlign) {
+                hAlign = setting.header[col].hAlign;
+            } else if (setting.header[col].dataType !== "String"){
+                hAlign = "right";
+            }
+            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            sheetCommonObj.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
+            if (setting.header[col].formatter) {
+                sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
+            }
+            if(setting.header[col].cellType === "comboBox"){
+                this.setComboBox(-1,col,sheet,setting.header[col].options,setting.header[col].editorValueType,setting.header[col].editable,setting.header[col].maxDropDownItems);
+            }
+
+            for (let row = 0; row < data.length; row++) {
+                if(data[row].cellType === 'comboBox'){
+                    let options = data[row].options ? data[row].options.split("@") : [];
+                    this.setComboBox(row,col,sheet,options);
+                }
+                let val = data[row][setting.header[col].dataCode];
+                if(val&&setting.header[col].dataType === "Number"){
+                    if(setting.header[col].hasOwnProperty('decimalField')){
+                        let decimal = getDecimal(setting.header[col].decimalField);
+                        val =scMathUtil.roundToString(val,decimal);
+                        sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
+                    }else {
+                        val =scMathUtil.roundToString(val,2);
+                    }
+                }
+                sheet.setValue(row, col, val, ch);
+                if(col==0){
+                    let treeType = sheetCommonObj.getTreeNodeCellType(data,row,parentMap);
+                    sheet.getCell(row, 0).cellType(treeType);
+                    visibleMap[data[row].ID] = treeType.collapsed;
+                    this.setRowVisible(data,row,visibleMap,sheet);
+                }
+                if(data[row].bgColour) styleRow.push(row)
+            }
+        }
+        for(let r of styleRow){
+            this.setRowStyle(r,sheet,data[r].bgColour);
+        }
+        this.lockCells(sheet,setting);
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
+    setRowVisible:function (data,row,visibleMap,sheet) {
+        sheet.getRange(row , -1, 1, -1).visible(getVisible(data[row].ParentID));//显示或隐藏
+        function getVisible(ParentID) {
+            if(visibleMap[ParentID]) return false //如果父节点是缩起的,那就隐藏本身。
+            if(visibleMap[ParentID] == false){//如果父节点不是缩起的,要再往父节点找看
+                let pnode = _.find(data,{'ID':ParentID});
+                if(pnode) return getVisible(pnode.ParentID);//如果有父节点,递归调用
+                return true;//没有,返回显示
+            }
+        }
+    },
     showData: function(sheet, setting, data,distTypeTree,callback) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
@@ -165,6 +231,14 @@ var sheetCommonObj = {
     },
     showRowData:function (sheet,setting,row,data,distTypeTree=null) {
         let ch = GC.Spread.Sheets.SheetArea.viewport;
+        if(data[row].cellType == "date"){//日期格式比较特殊,要判断数据里的属性,为data类型,同时读取列
+            this.setDatePickerCellType(row,data[row].dateCol,sheet)
+        }
+        if(data[row].cellType === 'comboBox'){//对于选项在数据里下拉框类型,同时读取列
+            let options = data[row].options ? data[row].options.split("@") : [];
+            this.setComboBox(row,data[row].dateCol,sheet,options);
+        }
+
         for (var col = 0; col < setting.header.length; col++) {
             //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
             var val = data[row][setting.header[col].dataCode];
@@ -184,7 +258,7 @@ var sheetCommonObj = {
                 this.setCheckBoxCell(row,col,sheet,val)
             }
             if(setting.header[col].cellType === "comboBox"){
-                this.setComboBox(row,col,sheet,setting.header[col].options,setting.header[col].editorValueType);
+                this.setComboBox(row,col,sheet,setting.header[col].options,setting.header[col].editorValueType,setting.header[col].editable,setting.header[col].maxDropDownItems);
             }
             if(setting.header[col].cellType === "selectButton"){
                 this.setSelectButton(row,col,sheet,setting.header[col]);
@@ -192,11 +266,9 @@ var sheetCommonObj = {
             if(setting.header[col].cellType === "replaceButton"){
                 this.setReplaceButton(row,col,sheet,setting.header[col]);
             }
-
             if(setting.header[col].cellType === "cusButton"){
                 this.setCusButton(row,col,sheet,setting);
             }
-
             if(setting.header[col].cellType === "tipsCell"){
                 this.setTipsCell(row,col,sheet,setting.header[col]);
             }
@@ -299,6 +371,15 @@ var sheetCommonObj = {
                 sheet.getRange(-1,col, -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
             }
         }
+        if (setting && Array.isArray(setting.view.lockRows) && setting.view.lockRows.length) {
+            if (!setting.view.lockColumns || !setting.view.lockColumns.length) {
+                sheet.options.isProtected = true;
+                sheet.getRange(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }
+            setting.view.lockRows.forEach(row => {
+                sheet.getRange(row, -1, 1, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+            });
+        }
     },
     setCheckBoxCell(row,col,sheet,val){
         var c = this.getCheckBox();
@@ -312,11 +393,13 @@ var sheetCommonObj = {
         c.isThreeState(threeState);
         return c
     },
-    setComboBox(row,col,sheet,options,editorValueType){
+    setComboBox(row,col,sheet,options,editorValueType,editable,maxDropDownItems){
         //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
         let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
         if(options){
             dynamicCombo.items(options);
+            if(maxDropDownItems) dynamicCombo.maxDropDownItems(maxDropDownItems);
+            if(editable == true)  dynamicCombo.editable(true);//可编辑
             if(editorValueType==true){
                 dynamicCombo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
             }
@@ -652,6 +735,55 @@ var sheetCommonObj = {
         cellType.buttonBackColor("#07A0FF");
         sheet.setCellType(row, col,cellType,GC.Spread.Sheets.SheetArea.viewport);
     },
+    setDatePickerCellType(row,col,sheet){
+        let ns = GC.Spread.Sheets;
+
+        function DatePickerCellType() {
+        }
+        DatePickerCellType.prototype = new GC.Spread.Sheets.CellTypes.Base();
+
+        DatePickerCellType.prototype.createEditorElement = function (context) {
+            //Create input presenter.
+            return document.createElement("input");
+        };
+        DatePickerCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) {
+            //Initialize input editor.
+            if (editorContext) {
+                $editor = $(editorContext);
+                //DatePickerCellType.prototype.activateEditor.apply(this, arguments);
+                $editor.datepicker({dateFormat: 'yy-mm-dd'});
+                $editor.css("position", "absolute");
+                $editor.attr("gcUIElement", "gcEditingInput");
+                $(".ui-datepicker").attr("gcUIElement", "gcEditingInput");
+            }
+        }
+        DatePickerCellType.prototype.deactivateEditor = function (editorContext, context) {
+            //Remove input editor when end editor status.
+            if (editorContext) {
+                var element = editorContext;
+                $(element).datepicker("hide");
+                $(element).datepicker("destroy");
+            }
+            // DatePickerCellType.prototype.deactivateEditor.apply(this, arguments)
+        };
+        DatePickerCellType.prototype.setEditorValue = function (editor, value, context) {
+            //Sync value from Cell value to editor value.
+            $(editor).datepicker("setDate", value);
+        };
+        DatePickerCellType.prototype.getEditorValue = function (editor, context) {
+            //Sync value from editor value to cell value.
+            return $(editor).datepicker("getDate");
+        };
+        DatePickerCellType.prototype.updateEditor = function (editorContext, cellStyle, cellRect, context) {
+            if (editorContext) {
+                $editor = $(editorContext);
+                $editor.css("width", cellRect.width - 1);
+                $editor.css("height", cellRect.height - 3);
+            }
+        };
+        let picker = new DatePickerCellType();
+        sheet.getCell(row, col).cellType(picker).width(100).formatter('yyyy-mm-dd');
+    },
 
     setTipsCell(row,col,sheet,header){
         let TipCellType = function () {};
@@ -783,7 +915,7 @@ var sheetCommonObj = {
 
         function TreeNodeCellType() {
             this.collapsed = gljUtil.isDef(datas[row].collapsed)?datas[row].collapsed: true; //默认是折叠的
-            this. treeNodeType = true;
+            this.treeNodeType = true;
             this.rectInfo = {};
         }
         TreeNodeCellType.prototype = new ns.CellTypes.Text();
@@ -823,6 +955,7 @@ var sheetCommonObj = {
             offset += rectW;
             x = x + offset;//设置偏移
             w = w - offset;
+            if(datas[row].foreColor) style.foreColor = datas[row].foreColor;
             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
         };
         // override getHitInfo to allow cell type get mouse messages
@@ -885,7 +1018,7 @@ var sheetCommonObj = {
         return new TreeNodeCellType()
 
         function getTreeLevel(item,data) {
-            if(item.ParentID){
+            if(item.ParentID && item.ParentID!=-1){
                 let pitem =  _.find(data,{'ID':item.ParentID});
                 return  getTreeLevel(pitem,data) + 1;
             }else {

+ 2 - 1
public/web/tree_sheet/tree_sheet_helper.js

@@ -181,7 +181,8 @@ var TREE_SHEET_HELPER = {
                 var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
                 if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
-                }else if(colSetting.data.field=="mainBills"&&MainTreeCol.mainBillsEnable(node)){//主要清单有三种状态,所以直接显示就好,不走最后的逻辑
+                }else if((colSetting.data.field=="mainBills"||(colSetting.data.field=="outPutMaxPrice" && $("#fileKind").val() != '1'))&&MainTreeCol.mainBillsEnable(node)){//主要清单有三种状态,所以直接显示就好,不走最后的逻辑
+                   //outPutMaxPrice 对于投标项目 即 fileKind = 1 时只读,不进这个逻辑
                     cell.value(node.data[colSetting.data.field]===undefined?false:node.data[colSetting.data.field]);
                 } else {
                     cell.value(getFieldText2());

+ 4 - 2
web/building_saas/css/custom.css

@@ -47,8 +47,6 @@ legend.legend{
 }
 
 .filterType{
-    padding-left: 6px;
-    padding-right: 6px;
     width: 122px;
 }
 
@@ -324,4 +322,8 @@ input.text-right{
 }
 .border_bottom{
     border-bottom:  1px solid #ccc
+}
+.export-check{
+    overflow: auto;
+    height: 400px;
 }

+ 11 - 1
web/building_saas/css/main.css

@@ -373,9 +373,19 @@ a{
         transform: translateX(10px);
     }
 }
+.gl-side.gl-side-lg{
+    width:200px;
+}
+.nav-side .nav-link{
+    padding:.5rem;
+}
+.nav-side .nav-link.active{
+    background:#ddd;
+    color:#333;
+}
 .gl-side{
     border-right:1px solid #ccc;
-    width:150px
+    width:120px
 }
 .bottom-content .tab-content .main-data-bottom{
     height: 300px;

+ 12 - 12
web/building_saas/glj/html/project_glj.html

@@ -9,17 +9,17 @@
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-unitFile"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#unitFile-save-as"><i class="fa fa-files-o"></i> 另存单独用</a></label>
         <select class="form-control form-control-sm" style="width: auto; font-size: .875rem ;color: #007bff" id="adjustType">
-            <option value="priceInfo">造价信息差额调整法</option>
-            <option value="priceCoe" selected>价格指数调整法</option>
+            <option value="priceInfo" selected>造价信息差额调整法</option>
+            <option value="priceCoe">价格指数调整法</option>
         </select>
     </div>
 </div>
 
 <div class="container-fluid">
     <div class="row">
-        <div class="gl-side  filterType" id='filterType'>
-            <ul class="nav flex-column nav-pills mt-2 mb-2">
-                <li class="nav-item"><a class="nav-link active" href="#" id="ALL">所有人材机</a></li>
+        <div class="gl-side  " id='filterType'>
+            <ul class="nav flex-column nav-side mt-2 mb-2" style="margin-top: 0px!important;">
+                <li class="nav-item" ><a class="nav-link active" href="#" id="ALL">所有人材机</a></li>
              <!--   <li class="nav-item li_sub"><a class="nav-link" href="javascript:void(0)" id="LABOUR">人工</a></li>
                 <li class="nav-item li_sub"><a class="nav-link" href="javascript:void(0)" id="GENERAL_MATERIAL">材料</a></li>
                 <li class="nav-item li_sub"><a class="nav-link" href="javascript:void(0)" id="GENERAL_MACHINE">机械</a></li>
@@ -31,7 +31,7 @@
                 <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="ZGCL">暂估材料</a></li>
                 <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="SCHZ">三材汇总</a></li>
                 <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="ZYCL">主要材料</a></li>
-                <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="AMAE">添加承包人提供主要材料和工程设备</a></li>
+                <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="AMAE">承包人主要材料设备</a></li>
             </ul>
         </div>
         <div class="main-content col p-0" id="material_adjust" style="overflow: hidden; display: none">
@@ -203,23 +203,23 @@
                             <label class="form-check-label" for="glj_sel_all">所有</label>
                         </div>
                         <div class="form-check form-check-inline">
-                            <input class="form-check-input glj_sel_input" type="checkbox" id="glj_sel_labour" value="1">
+                            <input class="form-check-input glj_sel_input glj_sel_input_other" type="checkbox" id="glj_sel_labour" value="1">
                             <label class="form-check-label" for="glj_sel_labour">人</label>
                         </div>
                         <div class="form-check form-check-inline">
-                            <input class="form-check-input glj_sel_input" type="checkbox" id="glj_sel_material" checked value="2">
+                            <input class="form-check-input glj_sel_input glj_sel_input_other" type="checkbox" id="glj_sel_material" checked value="2">
                             <label class="form-check-label" for="glj_sel_material">材</label>
                         </div>
                         <div class="form-check form-check-inline">
-                            <input class="form-check-input glj_sel_input" type="checkbox" id="glj_sel_machine" value="3">
+                            <input class="form-check-input glj_sel_input glj_sel_input_other" type="checkbox" id="glj_sel_machine" value="3">
                             <label class="form-check-label" for="glj_sel_machine">机</label>
                         </div>
                         <div class="form-check form-check-inline">
-                            <input class="form-check-input glj_sel_input" type="checkbox" id="glj_sel_main" checked value="4">
+                            <input class="form-check-input glj_sel_input glj_sel_input_other" type="checkbox" id="glj_sel_main" checked value="4">
                             <label class="form-check-label" for="glj_sel_main">主材</label>
                         </div>
                         <div class="form-check form-check-inline">
-                            <input class="form-check-input glj_sel_input" type="checkbox" id="glj_sel_eqp" checked value="5">
+                            <input class="form-check-input glj_sel_input glj_sel_input_other" type="checkbox" id="glj_sel_eqp" checked value="5">
                             <label class="form-check-label" for="glj_sel_eqp">设备</label>
                         </div>
                     </div>
@@ -229,8 +229,8 @@
                 </div>
             </div>
             <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
                 <button type="button" class="btn btn-primary" id="glj_sel_confirm" data-dismiss="modal">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
             </div>
         </div>
     </div>

+ 10 - 2
web/building_saas/js/global.js

@@ -1,7 +1,7 @@
 /*全局自适应高度*/
 function autoFlashHeight(){
     let headerHeight = $(".header").height();
-    let toolsbarHeight = $(".toolsbar").height();
+    let toolsbarHeight = getToolsbarHeight();
     let ftoolsbarHeight = $(".toolsbar-f").height();
     let btntoolsbarHeight = $(".btn-toolbar").height();
     // var feeRateToolsbarHeight = $(".toolsbar_feeRate").height();
@@ -19,6 +19,7 @@ function autoFlashHeight(){
     //$("#main .main-data-top").height($(window).height()-headerHeight-toolsbarHeight-bottomContentHeight-1);
     typeof(loadMainSize)== 'function' ?loadMainSize():'';//zhang 2018-06-04  统一加载高度方法
     typeof(loadProjectGljSize)== 'function'?loadProjectGljSize():'';
+    typeof(onResize)== 'function'?onResize():'';
     $(".main-data-full").height($(window).height()-headerHeight-toolsbarHeight-1);
     $(".main-data-full-fl").height($(window).height()-headerHeight-toolsbarHeight-37);
     $(".main-data-full-feeRate").height($(window).height()-headerHeight-78);
@@ -35,10 +36,17 @@ function autoFlashHeight(){
     typeof(adaptiveTzjnrWidth)== 'function' ?adaptiveTzjnrWidth():'';
     $('#project-glj-main').width($(window).width()-($('.main-nav').width()+ 2)-($('.filterType').width()+12)-5); //2、12是padding宽度,width 是不算padding宽度的
     $('#material_adjust').width($(window).width()-($('.main-nav').width()+ 2)-($('.filterType').width()+12)-5);//材料调差
+    $('#index_content').width($(window).width()-($('.main-nav').width()+ 2)-($('#index_nav').width()+12)-5);//材料调差
     //typeof zmhs_obj === 'object' ? zmhs_obj.loadSideResize() : '';
 };
 
-
+function getToolsbarHeight() {//动态获取toolsbar高度,由于页面有多个toolsbar高度,直接取取不到当前页的toolsbar
+    for(let t of $(".toolsbar")) {
+        let height = $(t).height();
+        if(height != -1) return height;
+    }
+    return 0;
+}
 
 /*全局自适应高度结束*/
 $(function () {

+ 28 - 0
web/building_saas/main/html/index_info.html

@@ -0,0 +1,28 @@
+<div >
+    <div class="toolsbar px-1 toolbar_index>">
+        <div class="form-inline py-1">
+            <label class="mx-2"><i class="fa fa-database mr-1" aria-hidden="true"></i>指标信息</label>
+        </div>
+    </div>
+    <div class="container-fluid">
+        <div class="row">
+            <div class="gl-side gl-side-lg" id="index_nav">
+                <ul class="nav flex-column nav-side mt-2 mb-2">
+                    <li class="nav-item"><a href="#" class="nav-link active">工程信息指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">工程特征指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">工程造价指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link ">主要工料指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">主要经济指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">主要工程量指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">设置主要经济、工程量指标</a></li>
+                    <li class="nav-item"><a href="#" class="nav-link">设置主要工料指标</a></li>
+                </ul>
+            </div>
+            <div class="main-content col p-0" id="index_content">
+                <div class="main-data-full" id="indexSpread"><!--spread js-->
+
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

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

@@ -53,6 +53,7 @@
         <span id="tool-toast-content">右键不支持粘贴外部内容,请使用Ctrl+V粘贴。<span id="toolToastBtn">我知道了</span></span>
     </div>
 </div>-->
+<input type="hidden" id="fileKind" value="<%= fileKind %>">
 <img src="/web/dest/css/img/question.png" id="question_pic" style="display: none">
     <div class="header">
          <div class="top-msg clearfix">
@@ -74,6 +75,7 @@
                 <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab" style="display:none">总计算程序</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab">调价</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#reports" role="tab" id="tab_report" onclick="rptTplObj.iniPage();">报表</a></li>
+                <li class="nav-item"><a data-toggle="tab" href="#index" id="tab_index" role="tab" style="display:none">指标信息</a></li>
             </ul>
         </div>
         <div class="content">
@@ -95,6 +97,13 @@
                             <a id="uploadGld" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入广联达算量Excel清单</a>
                         </div>
                     </span>
+                      <span id="exportSpan" class="btn btn-light btn-sm" data-toggle="tooltip" data-original-title="数据接口" data-placement="bottom">
+                    <a class="dropdown-toggle" href="#" data-toggle="dropdown"><i class="fa  fa-code-fork"></i></a>
+                    <div class="dropdown-menu" id="exportMenu">
+                        <a class="dropdown-item" href="#export" data-toggle="modal" data-target="#export">重庆市电子招投标数据接口</a>
+                        <a class="dropdown-item" href="javascript:void(0)" id="SEIMenu"  >导出重庆市指标成果文件</a>
+                    </div>
+                </span>
                     <a href="javascript:void(0)" class="btn btn-light btn-sm" id="insertRation" data-toggle="tooltip" data-placement="bottom" data-original-title="插入定额"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
                     <!--2018-11-15 隐藏删除按钮   <a href="javascript:void(0)" class="btn btn-light btn-sm" id="delete" data-toggle="tooltip" data-placement="bottom" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>-->
                     <a href="javascript:void(0)" class="btn btn-light btn-sm" id="upLevel" data-toggle="tooltip" data-placement="bottom" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
@@ -123,6 +132,7 @@
                               <% } %>
                               <a id="switchTznr" href="javascript:void(0);"  class="dropdown-item"><i class="fa fa-eye" aria-hidden="true"></i> 显示特征</a>
                               <a id = "menu_calc_program_manage"  href="javascript:void(0);" class="dropdown-item"><i class="fa fa-calculator" aria-hidden="true"></i> 总计算程序</a>
+                              <a id = "menu_index_info"  href="javascript:void(0);" class="dropdown-item"><i class="fa fa-database" aria-hidden="true"></i> 指标信息</a>
                           </div>
                       </div>
                  <!--   <span class="btn btn-light btn-sm">
@@ -761,10 +771,12 @@
             <div class="tab-pane" id="reports" role="tabpanel">
                 <%include ../../report/html/rpt_main.html %>
             </div>
-
             <div class="tab-pane" id="fee_rates" role="tabpanel">
                 <%include ../../fee_rates/fee_rate.html %>
             </div>
+              <div class="tab-pane" id="index" role="tabpanel">
+                  <%include index_info.html %>
+              </div>
               <div class="tab-pane" id="tender_price" role="tabpanel">
                   <%include tender_price.html %>
               </div>
@@ -1998,6 +2010,108 @@
             </div>
         </div>
     </div>
+<!--弹出 数据接口导出-->
+<div class="modal fade" id="export" data-backdrop="static">
+    <div class="modal-dialog" 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="card">
+                    <div class="card-body">
+                        <h5 class="card-title">导出重庆市电子招投标数据接口文件</h5>
+                        <p class="card-text">导出之前,建议您执行项目自检功能,避免出现错误。</p>
+                        <a id="export-check" href="javascript:void(0);" class="btn btn-primary">自检</a>
+                    </div>
+                </div>
+                <!--招标-->
+                <% if (fileKind == 2 || fileKind == 3) { %>
+                <div class="form-group">
+                    <label class="mb-0">招标接口文件导出</label>
+                    <small class="form-text text-muted">招标接口文件由以下2个文件组成,其内容必须保持一致,因此建议一次性全部导出。</small>
+                </div>
+                <div class="form-group">
+                    <div class="form-check ml-4">
+                        <input class="form-check-input" type="checkbox" value="2" id="ex-bid" checked>
+                        <label class="form-check-label" for="ex-bid">
+                            招标工程量清单
+                        </label>
+                        <small class="form-text text-muted">招标工程量清单数据文件,用于投标人投标报价</small>
+                    </div>
+                    <div class="form-check ml-4">
+                        <input class="form-check-input" type="checkbox" value="3" id="ex-control">
+                        <label class="form-check-label" for="ex-control">
+                            招标控制价
+                        </label>
+                        <small class="form-text text-muted">包含完整组价数据的招标控制价文件</small>
+                    </div>
+                </div>
+                <% } else { %>
+                <!--投标-->
+                <div class="form-group">
+                    <label class="mb-0">投标接口文件导出</label>
+                </div>
+                <div class="form-group">
+                    <div class="form-check ml-4">
+                        <input class="form-check-input" type="checkbox" value="1" id="ex-tender" checked>
+                        <label class="form-check-label" for="ex-tender">
+                            投标文件
+                        </label>
+                        <small class="form-text text-muted">投标工程数据文件</small>
+                    </div>
+                </div>
+                <% } %>
+            </div>
+            <div class="modal-footer">
+                <a id="export-confirm" href="javascript:void(0);" class="btn btn-primary">确定导出</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--设置导出工程编号-->
+<div class="modal fade" id="exportCode" data-backdrop="static">
+    <div class="modal-dialog" 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="modal-auto-height" style="overflow: hidden" id="exportSpread">
+                </div>
+                <p>*工程编号作为单项、单位工程的标识,要求在建设项目下唯一。</p>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary" id="exportCode-confirm">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--进度条-->
+<div class="modal fade" id="progress" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 id="progress-title" class="modal-title"></h5>
+            </div>
+            <div class="modal-body">
+                <h5 id="progress-content" class="my-3"></h5>
+                <div class="progress mb-3">
+                    <div class="progress-bar progress-bar-striped progress-bar-animated" id="progressBar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
 
     <img src="/web/dest/css/img/folder_open.png" id="folder_open_pic" style="display: none">
     <img src="/web/dest/css/img/folder_close.png" id="folder_close_pic" style="display: none">
@@ -2024,6 +2138,7 @@
     <script src="/lib/js-xlsx/xlsx.core.min.js"></script>
     <script src="/lib/lz-string/lz-string.min.js"></script>
     <script src="/lib/fileSaver/FileSaver.min.js"></script>
+    <script src="/lib/js-zip/jszip.min.js"></script>
     <!-- inject:js -->
     <!--<script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>-->
     <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
@@ -2086,6 +2201,7 @@
     <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/calc/calc_fees.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/exportStandardInterface.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/models/exportSEIInterface.js"></script>
     <!--<script type="text/javascript" src="/web/building_saas/main/js/calc/ration_calc.js"></script>-->
     <!--<script type="text/javascript" src="/web/building_saas/main/js/calc/bills_calc.js"></script>-->
     <!--<script type="text/javascript" src="/public/calc_util.js"></script>-->
@@ -2097,6 +2213,7 @@
     <script type="text/javascript" src="/web/building_saas/main/js/views/glj_col.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/main_tree_col.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/project_info.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/views/export_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/project_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/options_view.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_bills_quantity_decimal.js"></script>
@@ -2122,6 +2239,7 @@
     <script type="text/javascript" src='/web/building_saas/main/js/views/zlfb_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/installation_fee_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/material_adjust_view.js'></script>
+    <script type="text/javascript" src='/web/building_saas/main/js/views/index_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/project_glj_view.js'></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/importBills.js"></script>
     <!--报表-->

+ 29 - 0
web/building_saas/main/js/models/bills.js

@@ -213,6 +213,11 @@ var Bills = {
                     data.data.type = stdBillsData.type;//插入清单类型
                     //Vincent
                     data.data.billsLibId = stdBillsData.billsLibId;//添加清单库ID
+                    data.data.economicType = stdBillsData.economicType;//工程经济指标类别
+                    data.data.quantityIndexType = stdBillsData.quantityIndexType;//工程经济指标类别
+                    data.data.quantityIndexUnit = stdBillsData.quantityIndexUnit;//工程经济指标类别
+                    data.data.quantityIndexCoe = stdBillsData.quantityIndexCoe;//工程经济指标类别
+
                     //zhong
                     newData = data.data;
                 }
@@ -424,6 +429,12 @@ var Bills = {
                 node.data.ruleText = stdBillsData.ruleText;
                 // 说明(补注)
                 node.data.comments = stdBillsData.recharge;
+                node.data.economicType = stdBillsData.economicType;
+                node.data.quantityIndexType = stdBillsData.quantityIndexType;
+                node.data.quantityIndexUnit = stdBillsData.quantityIndexUnit;
+                node.data.quantityIndexCoe = stdBillsData.quantityIndexCoe;
+
+
                 // 工作内容
                /* node.data.jobContent = stdBillsData.jobContent;
                 node.data.jobContentText = stdBillsData.jobContentText;*/
@@ -617,6 +628,12 @@ var Bills = {
                 }
             }
         };
+        bills.prototype.getEngineeringCost = function () {//取项目工程造价;
+            let node =  this.getEngineeringCostNode(projectObj.mainController);
+            let totalFee = node && node.data.feesIndex && node.data.feesIndex.common?node.data.feesIndex.common.totalFee:0;
+            return totalFee;
+        };
+
         bills.prototype.getFBFXNode = function (controller) {//取分部分项工程节点
             let roots =  controller.tree.roots;
             for(let root of roots){
@@ -645,6 +662,18 @@ var Bills = {
            return techNode;
         };
 
+        bills.prototype.getOrgNode=function () {//取组织措施项目节点
+            let items = projectObj.project.mainTree.items;//所有节点;
+            let orgNode = null;
+            for(let item of items){
+                if(isFlag(item.data)&&item.data.flagsIndex.fixed.flag==fixedFlag.CONSTRUCTION_ORGANIZATION){
+                    orgNode = item;
+                    break;
+                }
+            }
+            return orgNode;
+        };
+
         bills.prototype.deleteSelectedNode=function(){//删除选中单行时的节点
             let controller = projectObj.mainController, project = projectObj.project;
             let selected = controller.tree.selected, parent = selected.parent;

+ 2 - 1
web/building_saas/main/js/models/cache_tree.js

@@ -475,8 +475,9 @@ var cacheTree = {
             }
             return success
         };
-        Tree.prototype.getAllSubNode = function (node,nodeArray) {
+        Tree.prototype.getAllSubNode = function (node,nodeArray,ignoreID) {
           for(let c of node.children){
+              if(ignoreID && c.data.ID == ignoreID) continue;
               nodeArray.push(c);
               this.getAllSubNode(c,nodeArray);
           }

+ 23 - 2
web/building_saas/main/js/models/calc_base.js

@@ -28,13 +28,21 @@ let cbTools = {
     //通过行获取根节点清单
     getBillByRow: function (items, row) {
         if(cbTools.isDef(items[row]) &&
-            cbTools.isUnDef(items[row]['parent'])&&
             cbTools.isDef(items[row]['sourceType']) &&
             items[row]['sourceType'] === calcBase.project.Bills.getSourceType()){
             return items[row];
         }
         return null;
     },
+    /*getBillByRow: function (items, row) {
+        if(cbTools.isDef(items[row]) &&
+            cbTools.isUnDef(items[row]['parent'])&&
+            cbTools.isDef(items[row]['sourceType']) &&
+            items[row]['sourceType'] === calcBase.project.Bills.getSourceType()){
+            return items[row];
+        }
+        return null;
+    },*/
     //通过ID获取节点行
     getRowByID: function (items, ID) {
         for(let i = 0, len = items.length; i < len; i++){
@@ -51,6 +59,7 @@ let cbTools = {
     //获取该节点所有父节点
     getParents: function (node) {
         let rst = [];
+        rst.push(node);
         rParent(node);
         return rst;
         function rParent(node){
@@ -60,6 +69,17 @@ let cbTools = {
             }
         }
     },
+    /*getParents: function (node) {
+        let rst = [];
+        rParent(node);
+        return rst;
+        function rParent(node){
+            if(cbTools.isDef(node.parent)){
+                rst.push(node.parent);
+                rParent(node.parent);
+            }
+        }
+    },*/
     //获取所有节点的ID
     getNodeIDs: function (nodes) {
         let rst = [];
@@ -1123,7 +1143,8 @@ let cbAnalyzer = {
             return false;
         }
         //用于判断的起始清单ID
-        let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
+        //let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
+        let sIDs = cbTools.getNodeIDs(cbTools.getParents(node));
         let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getUID(cbParser.getFIDArr(exp)));
         for(let i = 0, len = figureF.length; i < len; i++){
             let figure = figureF[i];

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

@@ -1982,7 +1982,6 @@ class CalcProgram {
                 if (node.children.length > 0) {
                     calcNodes(node.children);
                 };
-
                 if (calcType == calcAllType.catAll || calcType == node.sourceType) {
                     node.calcType = calcTools.getCalcType(node);
                     if (node.calcType != treeNodeCalcType.ctCalcBaseValue)

+ 569 - 0
web/building_saas/main/js/models/exportSEIInterface.js

@@ -0,0 +1,569 @@
+/**
+ * Created by zhang on 2019/5/20.
+ */
+
+let exportUtil = {
+    setEngineerPriceIndex:function (tender,projectData) {
+        let priceIndex = {
+            name:"工程造价指标",
+            attrs:[],
+            children:[],
+        };
+        let fixMap = {};
+        let buildingArea = this.getBuildArea(tender.property.engineerFeatures); //tender.property.projectFeature?getItemValueBykey(tender.property.projectFeature,"buildingArea"):1;//建筑面积
+
+        for(let b of projectData.bills){
+            if(b.flags && b.flags.length > 0){
+                let f = _.find(b.flags,{"fieldName":"fixed"});
+                if(f) fixMap[f.flag] = this.getTotalFee(b);
+            }
+        }
+        //计算其他组织措施费 = 施工组织措施项目下的子项,除了  安全文明施工费、建设工程竣工档案编制费以外的项
+        let CONSTRUCTION_ORGANIZATION = fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]?fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]:0;
+        let SAFETY_CONSTRUCTION =  fixMap[fixedFlag.SAFETY_CONSTRUCTION]?fixMap[fixedFlag.SAFETY_CONSTRUCTION]:0;
+        let PROJECT_COMPLETE_ARCH_FEE =  fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]? fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]:0;
+        let other_org_fee = CONSTRUCTION_ORGANIZATION - SAFETY_CONSTRUCTION - PROJECT_COMPLETE_ARCH_FEE;
+        other_org_fee = other_org_fee >0 ?other_org_fee:0;
+        let engineerCost = fixMap[fixedFlag.ENGINEERINGCOST]?fixMap[fixedFlag.ENGINEERINGCOST]:1;
+        priceIndex.children.push(this.getFlag("分部分项工程费",fixMap[fixedFlag.SUB_ENGINERRING],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("技术措施费",fixMap[fixedFlag.CONSTRUCTION_TECH],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("安全文明施工费",fixMap[fixedFlag.SAFETY_CONSTRUCTION],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("建设工程竣工档案编制费",fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("其他组织措施费",other_org_fee,engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("暂列金额",fixMap[fixedFlag.PROVISIONAL],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("专业工程暂估价",fixMap[fixedFlag.ENGINEERING_ESITIMATE],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("计日工",fixMap[fixedFlag.DAYWORK],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("总承包服务费",fixMap[fixedFlag.TURN_KEY_CONTRACT],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("索赔与现场签证",fixMap[fixedFlag.CLAIM_VISA],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("规费",fixMap[fixedFlag.CHARGE],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("税金",fixMap[fixedFlag.TAX],engineerCost,buildingArea));
+        priceIndex.children.push(this.getFlag("工程造价",fixMap[fixedFlag.ENGINEERINGCOST],engineerCost,buildingArea));
+        return priceIndex;
+    },
+    getTotalFee:function (b) {
+        let total = 0;
+        if(b.fees && b.fees.length > 0){
+            let common = _.find(b.fees,{"fieldName":"common"});
+            if(common) total = scMathUtil.roundForObj(common.totalFee,getDecimal("bills.totalPrice"))
+        }
+        return total;
+    },
+    getFlag: function (name,totalCost,engineerCost,buildingArea) {
+        totalCost = totalCost?totalCost:0;
+        let flag = {
+            name:name,
+            attrs:[
+                {name: "金额", value: scMathUtil.roundToString(totalCost,3)},
+                {name: "单方造价", value: scMathUtil.roundToString(exportUtil.calcUnitB(totalCost,buildingArea),2)},
+                {name: "占造价比例", value: scMathUtil.roundToString(totalCost/engineerCost * 100,2)},
+            ],
+        };
+        return flag;
+    },
+    getBuildArea:function (features) {
+        if(features){
+            let areas = [];
+            for(let f of features){
+                if(f.index == true && f.value && f.value !=="" && IsNumber(f.value)) areas.push(f.value);
+            }
+            return _.isEmpty(areas)?1:areas;
+        }
+        return 1
+    },
+    calcUnitB:function (total,building,coe,decimal = 3) {
+        if(Array.isArray(building)){
+            for(let b of building){
+                total = scMathUtil.roundForObj(total/b,6);
+            }
+        }else {
+            total = scMathUtil.roundForObj(total/building,6);
+        }
+        coe = gljUtil.isDef(coe)?coe:1;
+        return scMathUtil.roundForObj(total*coe,decimal);
+    },
+    calUnitWidthCoe:function (total,noNeedCoe) {
+        let areas = exportUtil.getBuildArea(projectObj.project.property.engineerFeatures);
+        let f = _.find(projectObj.project.property.engineerFeatures,{index:true});
+        return f && noNeedCoe!==true?exportUtil.calcUnitB(total,areas,f.coe):exportUtil.calcUnitB(total,areas);
+    },
+    getIndexBills:function (bills) {
+        let parentMap = {},datas = [],totalCost = 0;
+        let FBFX_b = null,teh_b = null,costNode=null;
+        for(let b of bills) {
+            parentMap[b.ParentID] ? parentMap[b.ParentID].push(b) : parentMap[b.ParentID] = [b];//有添加,无则生成
+            if(b.flags && b.flags.length > 0){
+                let f = _.find(b.flags,{"fieldName":"fixed"});
+                if(!f) continue;
+                if(f.flag == fixedFlag.SUB_ENGINERRING) FBFX_b = b;//过滤出分部分项工程;
+                if(f.flag == fixedFlag.CONSTRUCTION_TECH) teh_b = b;//过滤出技术措施项目;
+                if(f.flag == fixedFlag.ENGINEERINGCOST) costNode = b;//过滤出工程造价项目;
+            }
+        }
+        if(FBFX_b) getChildren(FBFX_b,parentMap,datas);
+        if(teh_b) getChildren(teh_b,parentMap,datas);
+        if(costNode) totalCost = exportUtil.getTotalFee(costNode);
+
+        for(let td of datas){
+            if(parentMap[td.ID]){
+                td.economicType = "";
+                td.quantityIndexType = "";
+                td.quantityIndexUnit = "";
+                td.quantityIndexCoe = "";
+            }
+        }
+        return [datas,totalCost];
+
+        function getChildren(d,map,arr) {
+            let tem = {
+                ID:d.ID,
+                ParentID:d.ParentID,
+                code:d.code,
+                name:d.name,
+                unit:d.unit,
+                quantity:d.quantity,
+                totalFee:exportUtil.getTotalFee(d),
+                economicType:d.economicType,
+                quantityIndexType:d.quantityIndexType,
+                quantityIndexUnit:d.quantityIndexUnit,
+                quantityIndexCoe:d.quantityIndexCoe,
+            };
+            arr.push(tem);
+            if(map[d.ID]){
+                for(let s of map[d.ID]){
+                    getChildren(s,map,arr)
+                }
+            }
+        }
+    }
+};
+
+async function exportSEI(projectID) {
+
+    let tenderProjects = [];
+    let result = await ajaxPost("/project/getSEIProjects",{projectID:projectID});
+    let pr = new SCComponent.InitProgressBar($('#progress'), $('#progress-title'), $('#progress-content'), $('#progressBar'));
+    pr.start('导出数据接口', '正在导出文件,请稍候……');
+    console.log(result);
+    let project = getProject(result);
+
+    await prepareTenderDatas(tenderProjects,project);
+
+
+    toXml(project);
+
+    pr.end();
+
+
+
+
+    function getProject(orignal) {//取建设项目信息
+        let basicInformation = getBaseInfo(orignal);
+        let project = {
+            name: "建设项目",
+            attrs: [
+                {name: "项目名称", value: orignal.name},
+                {name:"建设单位",value:getItemValueBykey(basicInformation.items,"constructionUnit")},
+                {name:"施工单位",value:getItemValueBykey(basicInformation.items,"buildingUnit")},
+                {name: "标准名称", value: "重庆市建设工程造价指标采集标准(清单计价)"},
+                {name: "标准版本号", value: "1.1"}
+            ],
+            basicInformation:basicInformation,
+            children:[]
+        };
+        initAtts(project.attrs);
+        for(let c of orignal.children){
+            project.children.push(getEngineering(c));
+        }
+        return project;
+    }
+
+    function getEngineering(source){
+        let engineer = {
+            name:"单项工程",
+            attrs:[
+                {name: "名称", value: source.name}
+            ],
+            children:[]
+        };
+
+        for(let c of source.children){
+            let tenderProject = getTender(c);
+            engineer.children.push(tenderProject);
+            tenderProjects.push(tenderProject);
+        }
+        return engineer
+    };
+
+    function getTender(source) {
+        let tender = {
+            ID:source.ID,
+            name:"单位工程",
+            attrs:[
+                {name: "名称", value: source.name}
+            ],
+            children:[],
+            valuationType:source.property.valuationType,
+            taxType:source.property.taxType,
+            property:source.property
+        };
+        return tender;
+    }
+
+
+    async function prepareTenderDatas(tenders,project) {
+        for(let t of tenders){
+            await setTenderData(t,project);
+        }
+
+
+    }
+
+    async function setTenderData(tender,project) {
+        let projectData = await ajaxPost("/project/loadSEIProjectData",{projectID:tender.ID});
+        tender.children.push(setEngineerInfo(tender));//设置工程信息
+        tender.children.push(setEngineerFeature(tender));//设置工程特征
+        tender.children.push(setEngineerIndex(tender,projectData));
+        tender.children.push(await setGLJSummy(tender,projectData));
+       //
+    }
+
+
+    function setEngineerIndex(tender,projectData) {//设置工程指标
+        let index = {
+            name:"工程指标",
+            attrs:[],
+            children:[],
+        };
+        let indexName = tender.property.indexName?tender.property.indexName:"建筑工程";
+        index.children.push(exportUtil.setEngineerPriceIndex(tender,projectData));
+        index.children.push(setEngineerEcoIndex(tender,projectData,indexName));
+        index.children.push(setMainMaterialIndex(tender,projectData,indexName));
+        index.children.push(setQuantityIndex(tender,projectData,indexName));
+
+        return index;
+
+        function setMainMaterialIndex(tender,projectData,indexName){
+            let mainIndex = {
+                name:`${indexName}工料指标`,
+                attrs:[],
+                children:[]
+            };
+            if(projectData) gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil);
+            let materials = indexObj.getMainMaterialDatas(tender.property.materials,projectData.projectGLJs,tender.property.calcOptions,tender.property.decimal,false,_,scMathUtil);
+            for(let m of materials){
+                mainIndex.children.push(getMaterial(m))
+            }
+            let index = {
+                name:"主要工料价格及消耗量指标",
+                attrs:[],
+                children:[mainIndex]
+            };
+            return index;
+
+            function getMaterial(m) {
+                let material = {
+                    name:m.name,
+                    attrs:[
+                        {name:"综合单价",value:scMathUtil.roundToString(m.unitPrice,2)},
+                        {name:"数量",value:scMathUtil.roundToString(m.quantity,2)},
+                        {name:"单方指标",value:scMathUtil.roundToString(m.unitIndex,3)},
+                        {name:"单位",value:m.unit}
+                    ]
+                };
+                return material;
+            }
+
+        }
+
+        function setQuantityIndex(tender,projectData,indexName) {
+            let quantityIndex = {
+                name:`${indexName}量指标`,
+                attrs:[],
+                children:[]
+            };
+            let quantities = indexObj.getQuantityDatas(tender.property.mainQuantities,projectData.bills);
+            for(let q of quantities){
+                quantityIndex.children.push(getQuantity(q));
+            }
+
+            let index = {
+                name:`主要工程量指标`,
+                attrs:[],
+                children:[quantityIndex]
+            };
+            return index;
+
+            function getQuantity(q) {
+                let quantity = {
+                    name:q.name,
+                    attrs:[
+                        {name:"工程量指标",value:scMathUtil.roundToString(q.quantity,3)},
+                        {name:"单位",value:q.unit}
+                    ]
+                };
+                return quantity;
+            }
+        }
+
+        function setEngineerEcoIndex(tender,projectData,indexName) {
+            let ecoIndex = {
+                name:`${indexName}经济指标`,
+                attrs:[],
+                children:[]
+            };
+            let economicDatas = indexObj.getEconomicDatas(tender.property.economics,projectData.bills);
+            for(let e of economicDatas){
+                ecoIndex.children.push(getEco(e))
+            }
+            let index = {
+                name:`工程经济指标`,
+                attrs:[],
+                children:[ecoIndex]
+            };
+            return index;
+
+            function getEco(e) {
+                let eco = {
+                  name:e.name,
+                  attrs:[
+                      {name:"综合合价",value:scMathUtil.roundToString(e.cost,2)},
+                      {name:"单方指标",value:scMathUtil.roundToString(e.unitCost,2)},
+                      {name:"占造价比例",value:scMathUtil.roundToString(e.per,2)}
+                  ]
+                };
+                return eco;
+            }
+        }
+    }
+
+    async function setGLJSummy(tender,projectData) {
+
+        let gljs = {
+            name:"人材机汇总",
+            attrs:[],
+            children:[]
+        };
+        setGLJDetail(projectData,tender.property,gljs);
+        return gljs;
+    }
+
+    function setGLJDetail(projectData,property,gljs) {
+        if(projectData){
+            gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil);
+        }
+        for(let g of projectData.projectGLJs.gljList) {
+            if (!g.quantity || g.quantity == "") continue;
+            g.marketPrice = gljUtil.getMarketPrice(g,projectData.projectGLJs,property.calcOptions,property.decimal,false,_,scMathUtil);
+            gljs.children.push(setEachGLJ(g));
+        }
+    }
+
+    function setEachGLJ(source){
+        let g = {
+            name:"人材机",
+            attrs:[
+                {name: "代码", value: source.code},
+                {name: "名称", value: source.name},
+                {name: "规格型号", value: source.specs},
+                {name: "单位", value: source.unit},
+                {name: "市场单价", value: source.marketPrice},
+                {name: "数量", value: source.quantity},
+                {name: "类型", value: source.type},
+                {name: "产地", value: source.originPlace},
+                {name: "厂家", value: source.vender},
+                {name: "备注", value: source.remark}
+            ]
+        };
+        return g;
+    }
+
+
+
+    function setEngineerInfo(tender) {//设置工程信息
+        let infos = tender.property.engineerInfos?tender.property.engineerInfos:[];
+        let info = {
+            name:"工程信息",
+            attrs:[
+                {name:"造价编制单位",value:getItemValueByDispName(infos,"造价编制单位")},
+                {name:"造价审核单位",value:getItemValueByDispName(infos,"造价审核单位")},
+                {name:"项目负责人",value:getItemValueByDispName(infos,"项目负责人")},
+                {name:"施工单位编制人员",value:getItemValueByDispName(infos,"施工单位编制人员")},
+                {name:"编制人员",value:getItemValueByDispName(infos,"编制人员")},
+                {name:"审核人员",value:getItemValueByDispName(infos,"审核人员")},
+                {name:"开工日期",value:getItemValueByDispName(infos,"开工日期")},
+                {name:"竣工日期",value:getItemValueByDispName(infos,"竣工日期")},
+                {name:"工程地点",value:getItemValueByDispName(infos,"工程地点")},
+                {name:"工程类型",value:getItemValueByDispName(infos,"工程类型")},
+                {name:"合同价类型",value:getItemValueByDispName(infos,"合同价类型")},
+                {name:"造价类型",value:getItemValueByDispName(infos,"造价类型")},
+                {name:"计价方式及依据",value:getItemValueByDispName(infos,"计价方式及依据")},
+                {name:"工程类别",value:getItemValueByDispName(infos,"工程类别")},
+                {name:"编制日期",value:getItemValueByDispName(infos,"编制日期")},
+                {name:"审查日期",value:getItemValueByDispName(infos,"审查日期")}
+
+            ]
+        };
+        initAtts(info.attrs);
+        return info;
+    }
+
+    function setEngineerFeature(tender) {
+        let fea = {
+            name:"工程特征",
+            attrs:[],
+            children:[]
+        };
+        fea.children.push(setIndexName(tender));
+        return fea;
+
+        function setIndexName(tender) {
+            let indexName = {
+                name:tender.property.indexName?tender.property.indexName:"建筑工程",
+                attrs:[],
+                children:[]
+            };
+            setFeatures(tender,indexName.children);
+            return indexName
+        }
+        function setFeatures(tender,arr) {
+            let features = tender.property.engineerFeatures?tender.property.engineerFeatures:[];
+            if(features.length == 0) return;
+            let parentMap = _.groupBy(features,"ParentID");
+            let rootNodes = parentMap["-1"]?parentMap["-1"]:parentMap[null];
+            for(let r of rootNodes){
+                arr.push(getFeatrue(r,parentMap))
+            }
+        }
+
+        function getFeatrue(node,parentMap){
+            if(parentMap[node.ID]){//如果有子节点,那么它就是一个节点
+                let tem = {
+                    name:node.name.replace("*",""),
+                    attrs:[],
+                    children:[]
+                };
+                for(let s of parentMap[node.ID]){
+                    let f = getFeatrue(s,parentMap);
+                    f.children?tem.children.push(f):tem.attrs.push(f);//如果有children这个属性,则返回的是一个节点,如果没有,则返回的是一个属性
+                }
+                return tem;
+            }else {//如果没有子节点,那么它就是父节点的一个属性
+                return {name:node.name.replace("*",""),value:node.value};
+            }
+        }
+    }
+
+
+    function getBaseInfo(project){
+        let basicInformation = {items:[]};
+        let tem = null;
+        if(project.property&&project.property.basicInformation) tem =_.find(project.property.basicInformation,{"key":"basicInfo"});
+        if(tem) basicInformation = tem;
+        return basicInformation;
+    }
+
+
+    function getItemValueBykey(items,key) {
+        let item = _.find(items,{"key":key});
+        if(item) return item.value;
+        return ""
+    }
+    function getItemValueByDispName(items,dispName) {
+        let item = _.find(items,{"dispName":dispName});
+        if(item) return item.value;
+        return ""
+    }
+
+    function initAtts(arrs) {
+        _.remove(arrs,function (item) {
+            return item.required == false && _.isEmpty(item.value)
+        })
+    }
+
+    //开始标签
+    function startTag(ele) {
+        let rst = `<${ele.name}`;
+        for (let attr of ele.attrs) {
+            rst += ` ${attr.name}="${ attr.value!=undefined&&attr.value!= null?attr.value:""}"`;
+        }
+        rst += ele.children&&ele.children.length > 0 ? '>' : '/>';
+        return rst;
+    }
+    //结束标签
+    function endTag(ele) {
+        return `</${ele.name}>`;
+    }
+    //拼接成xml字符串
+    function toXMLStr(eles) {
+        let rst = '';
+        for (let ele of eles) {
+            rst += startTag(ele);
+            if (ele.children&& ele.children.length > 0) {
+                rst += toXMLStr(ele.children);
+                rst += endTag(ele);
+            }
+        }
+        return rst;
+    }
+    //格式化xml字符串
+    function formatXml(text) {
+        //去掉多余的空格
+        text = '\n' + text.replace(/>\s*?</g, ">\n<");
+        //调整格式
+        let rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/mg;
+        let nodeStack = [];
+        let output = text.replace(rgx, function($0, all, name, isBegin, isCloseFull1, isCloseFull2, isFull1, isFull2){
+            let isClosed = (isCloseFull1 === '/') || (isCloseFull2 === '/' ) || (isFull1 === '/') || (isFull2 === '/');
+            let prefix = '';
+            if (isBegin === '!') {
+                prefix = getPrefix(nodeStack.length);
+            } else {
+                if (isBegin !== '/') {
+                    prefix = getPrefix(nodeStack.length);
+                    if (!isClosed) {
+                        nodeStack.push(name);
+                    }
+                } else {
+                    nodeStack.pop();
+                    prefix = getPrefix(nodeStack.length);
+                }
+            }
+            let ret =  '\n' + prefix + all;
+            return ret;
+        });
+        let outputText = output.substring(1);
+        return outputText;
+        function getPrefix(prefixIndex) {
+            let span = '    ';
+            let output = [];
+            for (let i = 0 ; i < prefixIndex; ++i) {
+                output.push(span);
+            }
+            return output.join('');
+        }
+    }
+    /*
+     * 导出数据
+     * @param {Number}tenderID(当前界面的单位工程ID,后台根据这个单位工程,根据导出粒度去找其建设项目下相关数据)
+     * @return {void}
+     * */
+     function toXml(eleData) {
+         //转换成xml字符串
+         let xmlStr = toXMLStr([eleData]);
+         //加上xml声明
+         xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
+         //格式化
+         xmlStr = formatXml(xmlStr);
+         let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
+         saveAs(blob, '经济指标.ZBF');
+     }
+
+}
+
+$(function () {
+   $("#SEIMenu").click(async function () {
+       await exportSEI(projectObj.project.property.rootProjectID);
+       $("#exportMenu").removeClass("show");
+   })
+
+});

File diff suppressed because it is too large
+ 780 - 223
web/building_saas/main/js/models/exportStandardInterface.js


File diff suppressed because it is too large
+ 1506 - 36
web/building_saas/main/js/models/importStandardInterface.js


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

@@ -268,7 +268,9 @@ const fixedFlag = {
     //建设工程竣工档案编制费
     PROJECT_COMPLETE_ARCH_FEE:30,
     //住宅工程质量分户验收费
-    HOUSE_QUALITY_ACCEPT_FEE:31
+    HOUSE_QUALITY_ACCEPT_FEE:31,
+    //组织措施费
+    ORGANIZATION:32,
 };
 const gljKeyArray =['code','name','specs','unit','type'];
 const rationKeyArray =['code','name','specs','unit','subType'];

+ 25 - 16
web/building_saas/main/js/models/project.js

@@ -397,15 +397,13 @@ var PROJECT = {
             }
             return true;
         };
-        project.prototype.updateMainBills = function(node,newval){
+        project.prototype.updateCasCadeBills = function(node,newval,fieldName){
             let datas = [];
             let data =  {
                 type:node.sourceType,
-                data:{
-                    ID:node.data.ID,
-                    mainBills:newval
-                }
+                data:{ID:node.data.ID}
             };
+            setData(data.data,newval,fieldName);
             datas.push(data);
             setChildren(node,newval,datas);//同步设置所有子项
             setParent(node,newval,datas);//设置父节点
@@ -415,7 +413,10 @@ var PROJECT = {
                 for(let d of datas){
                     let node = projectObj.project.mainTree.findNode(d.data.ID);
                     if(node){
-                        node.data.mainBills = d.data.mainBills;
+                        for(let key in d.data){
+                            if(key == 'ID') continue;
+                            node.data[key] = d.data[key];
+                        }
                         nodes.push(node)
                     }
                 }
@@ -428,11 +429,9 @@ var PROJECT = {
                     for(let c of pnode.children){
                         let data =  {
                             type:c.sourceType,
-                            data:{
-                                ID:c.data.ID,
-                                mainBills:newValue
-                            }
+                            data:{ID:c.data.ID}
                         };
+                        setData(data.data,newval,fieldName);
                         datas.push(data);
                         setChildren(c,newValue,datas)
                     }
@@ -443,7 +442,7 @@ var PROJECT = {
                 if(cnode.parent && !projectObj.project.Bills.isMeasureNode(cnode.parent)){//排除措施项目节点
                     for(b of cnode.parent.children){
                         if(b == cnode) continue
-                        if(b.data.mainBills!== newValue){//有兄弟节点的值和本节点不一样,则父节点设置为null
+                        if(b.data[fieldName]!== newValue){//有兄弟节点的值和本节点不一样,则父节点设置为null
                             diferrent = true;
                             break;
                         }
@@ -451,18 +450,26 @@ var PROJECT = {
                     let pvalue = diferrent === true?null:newValue;
                     let data =  {
                         type:cnode.parent.sourceType,
-                        data:{
-                            ID:cnode.parent.data.ID,
-                            mainBills:pvalue
-                        }
+                        data:{ID:cnode.parent.data.ID}
                     };
+                    setData(data.data,pvalue,fieldName);
                     datas.push(data);
                     setParent(cnode.parent,pvalue,datas);
                 }
             }
+            function setData(data,avalue,fieldName) {
+                data[fieldName] = avalue;
+                if(fieldName == "outPutMaxPrice") data.maxPrice = null;
+            }
 
         };
-
+        project.prototype.updateNodesAndRefresh=function (datas,callback) {
+            let me = this;
+            this.updateNodes(datas,function () {
+                let nodes = me.updateNodesCache(datas);
+                if(callback) callback(nodes);
+            })
+        };
 
         project.prototype.updateNodes = function (datas,callback) {
           /*  let datas = [
@@ -483,9 +490,11 @@ var PROJECT = {
                     }
                 }
             ]*/
+          $.bootstrapLoading.start();
             CommonAjax.post("/project/updateNodes",datas,function (data) {
                 if(callback){
                     callback(data);
+                    $.bootstrapLoading.end();
                 }
             })
         };

+ 5 - 4
web/building_saas/main/js/models/project_glj.js

@@ -537,6 +537,9 @@ ProjectGLJ.prototype.addMixRatio = function(selections,callback){
                 repositoryId:glj.repositoryId,
                 materialType:glj.materialType,
                 materialCoe:glj.materialCoe,
+                materialIndexType:glj.materialIndexType,
+                materialIndexUnit:glj.materialIndexUnit,
+                materialIndexCoe:glj.materialIndexCoe
             };
             if (glj.hasOwnProperty("compilationId")) {
                 pglj.from = "cpt";
@@ -827,20 +830,18 @@ ProjectGLJ.prototype.getMarketPrice = function (glj,isRadio) {
     let proGLJ =  projectObj.project.projectGLJ;
     let calcOptions=projectObj.project.projectInfo.property.calcOptions;
     let decimalObj = projectObj.project.projectInfo.property.decimal;
-    let labourCoeDatas =  projectObj.project.labourCoe.datas;
-    return gljUtil.getMarketPrice(glj,proGLJ.datas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
+    return gljUtil.getMarketPrice(glj,proGLJ.datas,calcOptions,decimalObj,isRadio,_,scMathUtil);
 };
 
 ProjectGLJ.prototype.getTenderMarketPrice = function (glj,isRadio) {
     let proGLJ =  projectObj.project.projectGLJ;
     let calcOptions=projectObj.project.projectInfo.property.calcOptions;
     let decimalObj = projectObj.project.projectInfo.property.decimal;
-    let labourCoeDatas =  projectObj.project.labourCoe.datas;
     let tenderCoe = 1;
     if (projectObj.project.property.tenderSetting && gljUtil.isDef(projectObj.project.property.tenderSetting.gljPriceTenderCoe) ){
         tenderCoe = parseFloat(projectObj.project.property.tenderSetting.gljPriceTenderCoe);
     }
-    return gljUtil.getMarketPrice(glj,proGLJ.datas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil,tenderCoe);
+    return gljUtil.getMarketPrice(glj,proGLJ.datas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe);
 };
 
 ProjectGLJ.prototype.isEstimateType = function(type){

+ 12 - 0
web/building_saas/main/js/models/ration_glj.js

@@ -584,6 +584,9 @@ let ration_glj = {
                         adjCoe: glj.adjCoe,
                         materialType:glj.materialType,
                         materialCoe:glj.materialCoe,
+                        materialIndexType:glj.materialIndexType,
+                        materialIndexUnit:glj.materialIndexUnit,
+                        materialIndexCoe:glj.materialIndexCoe,
                         repositoryId: glj.repositoryId
                     };
                     if(pEngineer) new_glj.programID = pEngineer;
@@ -663,6 +666,9 @@ let ration_glj = {
                 createType: 'add',
                 materialType:glj.materialType,
                 materialCoe:glj.materialCoe,
+                materialIndexType:glj.materialIndexType,
+                materialIndexUnit:glj.materialIndexUnit,
+                materialIndexCoe:glj.materialIndexCoe,
                 repositoryId: glj.repositoryId
             };
             if (glj.hasOwnProperty("compilationId")) {
@@ -766,6 +772,9 @@ let ration_glj = {
             oldData.repositoryId = glj.repositoryId;
             oldData.materialType = glj.materialType;
             oldData. materialCoe =  glj.materialCoe;
+            oldData. materialIndexType =  glj.materialIndexType;
+            oldData. materialIndexUnit =  glj.materialIndexUnit;
+            oldData. materialIndexCoe =  glj.materialIndexCoe;
             if (glj.hasOwnProperty("compilationId")) {
                 oldData.from = "cpt";
                 if (glj.code.indexOf('-') != -1) {//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
@@ -830,6 +839,9 @@ let ration_glj = {
                 repositoryId: glj.repositoryId,
                 materialType: glj.materialType,   //三材类别
                 materialCoe: glj.materialCoe,
+                materialIndexType: glj.materialIndexType,
+                materialIndexUnit: glj.materialIndexUnit,
+                materialIndexCoe: glj.materialIndexCoe,
                 projectID: oldData.projectID
             };
             if (glj.hasOwnProperty("compilationId")) {

+ 206 - 0
web/building_saas/main/js/views/export_view.js

@@ -0,0 +1,206 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/6/5
+ * @version
+ */
+//导出接口相关
+const ExportView = (() => {
+    let xmlObj = null;
+    //设置工程编号表格数据设置
+    const sheetSetting = {
+        header: [
+            {headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String'},
+            {headerName: '工程编号', headerWidth: 200, dataCode: 'code', dataType: 'String'},
+        ],
+        view: {
+            lockColumns: ['name'],
+            lockRows: [0]
+        }
+    };
+    //操作状态
+    const STATE = {
+        checking: false,    //自检
+        exporting: false,   //导出
+        confirming: false   //导出确认
+    };
+    let spread = null;
+    //初始化设置工程编号表格
+    function initSpread(datas) {
+        if (spread) {
+            return;
+        }
+        spread = SheetDataHelper.createNewSpread($("#exportSpread")[0], 1);
+        sheetCommonObj.spreadDefaultStyle(spread);
+        let sheet = spread.getSheet(0);
+        sheetCommonObj.initSheet(sheet, sheetSetting, 30);
+        sheet.setRowCount(datas.length);
+        sheetCommonObj.showTreeData(sheet, sheetSetting, datas);
+    }
+    //获取设置的工程编号
+    function getCodeFromSheet(sheet) {
+        let codeCol = 1;
+        let rst = [];
+        //排除建设项目行
+        for (let row = 1; row < sheet.getRowCount(); row++) {
+            rst.push(sheet.getValue(row, codeCol) || '');
+        }
+        return rst;
+    }
+    //事件监听
+    function exportListener() {
+        //导出接口-项目自检
+        $('#export-check').click(async function () {
+            let checkedDatas = $('#export input[type="checkbox"]:checked');
+            if (!checkedDatas.length) {
+                return;
+            }
+            if (STATE.checking) {
+                return;
+            }
+            STATE.checking = true;
+            let pr = new SCComponent.InitProgressBar();
+            try {
+                if (!xmlObj || !xmlObj.originalDatas.length) {
+                    pr.start('导出数据接口', '正在自检,请稍候……');
+                    xmlObj = new XMLStandard(userID, 1);
+                    for (let checkedData of checkedDatas) {
+                        let fileKind = $(checkedData).val();
+                        await xmlObj.toXml(projectObj.project.ID(), fileKind);
+                    }
+                }
+                //设置提示弹窗
+                if (xmlObj.failList.length * 20 > 400) {
+                    $('#hintBox_caption').addClass('export-check');
+                }
+                if (xmlObj.failList.length) {
+                    throw xmlObj.failList.join('<br/>');
+                }
+            } catch (err) {
+                alert(err);
+            }
+            pr.end();
+            setTimeout(() => {
+                STATE.checking = false;
+            }, 300);
+        });
+
+        //导出接口,如果没有错误,弹出工程编号设置窗口
+        $('#export-confirm').click(async function () {
+            let checkedDatas = $('#export input[type="checkbox"]:checked');
+            if (!checkedDatas.length) {
+                return;
+            }
+            if (STATE.exporting) {
+                return;
+            }
+            STATE.exporting = true;
+            let pr = new SCComponent.InitProgressBar();
+            try {
+                let isPring = false;    //是否调用了进度条(控制工程窗口什么时候显示,优化交互)
+                if (!xmlObj || !xmlObj.originalDatas.length) {
+                    isPring = true;
+                    pr.start('导出数据接口', '正在导出文件,请稍候……');
+                    xmlObj = new XMLStandard(userID, 1);
+                    for (let checkedData of checkedDatas) {
+                        let fileKind = $(checkedData).val();
+                        await xmlObj.toXml(projectObj.project.ID(), fileKind);
+                    }
+                    pr.end();
+                }
+                //错误-设置提示弹窗
+                if (xmlObj.failList.length * 20 > 400) {
+                    $('#hintBox_caption').addClass('export-check');
+                }
+                if (xmlObj.failList.length) {
+                    throw xmlObj.failList.join('<br/>');
+                }
+                //弹出工程编号设置窗口
+                if (isPring) {
+                    setTimeout(() => {
+                        $('#exportCode').modal('show');
+                    }, 300);
+                } else {
+                    $('#exportCode').modal('show');
+                }
+            } catch (err) {
+                pr.end();
+                alert(err);
+            }
+            setTimeout(() => {
+                STATE.exporting = false;
+            }, 300);
+        });
+        //工程编号设置窗口-----
+        //设置工程编号
+        $('#exportCode').on('shown.bs.modal', function () {
+            if (!xmlObj) {
+                alert('数据错误!');
+                $(this).modal('hide');
+                return false;
+            }
+            initSpread(xmlObj.getSheetData(xmlObj.PMData));
+        });
+        //设置完工程编号后,导出数据。如果选中多个文件,导出压缩包
+        $('#exportCode-confirm').click(async function () {
+            if (!spread || !xmlObj) {
+                return false;
+            }
+            if (STATE.confirming) {
+                return;
+            }
+            STATE.confirming = true;
+            let pr = new SCComponent.InitProgressBar();
+            try {
+                let codeDatas = getCodeFromSheet(spread.getSheet(0));
+                if (codeDatas.includes('')) {
+                    alert('单项、单位工程工程编号不可为空。');
+                    STATE.confirming = false;
+                    return false;
+                }
+                if ([...new Set(codeDatas)].length !== codeDatas.length) {
+                    alert('单项、单位工程工程编号必须唯一。');
+                    STATE.confirming = false;
+                    return false;
+                }
+                xmlObj.setupCode(codeDatas);
+                pr.start('导出数据接口', '正在导出文件,请稍候……');
+                await xmlObj.exportFile();
+            } catch (err) {
+                alert(err);
+            }
+            console.log(xmlObj);
+            pr.end();
+            $('#exportCode').modal('hide');
+            $('#export').modal('hide');
+            setTimeout(() => {
+                STATE.confirming = false;
+            }, 300);
+
+        });
+        //导出窗口--------
+        $('#export').on('show.bs.modal', function () {
+            xmlObj = null;
+        });
+        $('#export').on('hide.bs.modal', function() {
+            xmlObj = null;
+            STATE.checking = false;
+            STATE.exporting = false;
+            STATE.confirming = false;
+            //恢复设置提示弹窗 因为是共用的alert
+            $('#hintBox_caption').removeClass('export-check');
+            $('#export input[type="checkbox"]:eq(0)').prop('checked', true);
+            if (spread) {
+                spread.destroy();
+                spread = null;
+            }
+        });
+        $('#export input[type="checkbox"]').click(function () {
+            xmlObj = null;
+        });
+    }
+    return {exportListener}
+})();

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

@@ -139,7 +139,7 @@ var feeRateObject={
         feeRateObject.feeRateSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick,feeRateObject.onCellDoubleClick);
     },
     showFeeRateTree:function (sheet,setting,data) {
-
+        console.log(data);
         let ch = GC.Spread.Sheets.SheetArea.viewport;
         let parentMap=_.groupBy(data, 'ParentID');
         let visibleMap = {};

+ 725 - 0
web/building_saas/main/js/views/index_view.js

@@ -0,0 +1,725 @@
+/**
+ * Created by zhang on 2019/5/28.
+ */
+
+let indexObj= {
+    nav_text:"工程信息指标",
+    spread:null,
+    engineerInfoSetting:{
+        header: [
+            {headerName: "名称", headerWidth: 160, dataCode: "dispName", dataType: "String"},
+            {headerName: "内容", headerWidth: 200, dataCode: "value", dataType: "String"}
+        ],
+        view:{ lockColumns: ["dispName"]}
+    },
+    engineerFeatureSetting:{
+        header: [
+            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+            {headerName: "内容", headerWidth: 200, dataCode: "value", dataType: "String"}
+        ],
+        view:{ lockColumns: [0]}
+    },
+    engineerCostSetting:{
+        header: [
+            {headerName: "名称", headerWidth: 200, dataCode: "name", dataType: "String"},
+            {headerName: "金额", headerWidth: 160, dataCode: "cost", dataType: "String", hAlign: "right"},
+            {headerName: "单方造价", headerWidth: 160, dataCode: "unitCost", dataType: "String", hAlign: "right"},
+            {headerName: "占造价比例", headerWidth: 160, dataCode: "per", dataType: "String", hAlign: "right"}
+        ],
+        view:{ lockColumns: ["name","cost","unitCost","per"]}
+    },
+    mainMaterialSetting:{
+        header: [
+            {headerName: "名称", headerWidth: 200, dataCode: "name", dataType: "String"},
+            {headerName: "单位", headerWidth: 200, dataCode: "unit", dataType: "String"},
+            {headerName: "综合单价", headerWidth: 160, dataCode: "unitPrice", dataType: "String", hAlign: "right"},
+            {headerName: "数量", headerWidth: 160, dataCode: "quantity", dataType: "String", hAlign: "right"},
+            {headerName: "单方指标", headerWidth: 160, dataCode: "unitIndex", dataType: "String", hAlign: "right"}
+        ],
+        view:{ lockColumns: ["name","unit","unitPrice","quantity","unitIndex"]}
+    },
+    economicSetting:{
+        header: [
+            {headerName: "分部分项", headerWidth: 200, dataCode: "name", dataType: "String"},
+            {headerName: "分部工程造价", headerWidth: 160, dataCode: "cost", dataType: "String", hAlign: "right"},
+            {headerName: "单方指标", headerWidth: 160, dataCode: "unitCost", dataType: "String", hAlign: "right"},
+            {headerName: "占造价比例", headerWidth: 160, dataCode: "per", dataType: "String", hAlign: "right"}
+        ],
+        view:{ lockColumns: ["name","cost","unitCost","per"]}
+    },
+    quantitySetting:{
+        header: [
+            {headerName: "名称", headerWidth: 200, dataCode: "name", dataType: "String"},
+            {headerName: "工程量指标", headerWidth: 160, dataCode: "quantity", dataType: "String", hAlign: "right"},
+            {headerName: "单位", headerWidth: 160, dataCode: "quantityIndexUnit", dataType: "String", hAlign: "center"}
+        ],
+        view:{ lockColumns: ["name","quantity","quantityIndexUnit"]}
+    },
+    materialSetting:{
+        header: [
+            {headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String"},
+            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell'},
+            {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+            {headerName: "数量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity'},
+            {headerName: "市场价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+            {headerName: "市场价合价", headerWidth: 120, dataCode: "totalPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+            {headerName: "工料指标", headerWidth: 120, dataCode: "materialIndexType", hAlign: "center", dataType: "String",cellType:'comboBox',options:[],editable:true,maxDropDownItems:10},
+            {headerName: "工料指标单位", headerWidth: 150, dataCode: "materialIndexUnit", hAlign: "center", dataType: "String"},
+            {headerName: "单位转换系数", headerWidth: 150, dataCode: "materialIndexCoe", hAlign: "center", dataType: "String",validator:"number"}
+        ],
+        view: {
+            lockColumns: ["code","name","specs","unit","marketPrice","quantity","materialIndexUnit"]
+        }
+    },
+    ecoQuantitySetting:{
+        header: [
+            {headerName: "编码", headerWidth: 200, dataCode: "code", dataType: "String"},
+            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+            {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+            {headerName: "工程量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number"},
+            {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+            {headerName: "综合合价", headerWidth: 120, dataCode: "totalFee", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+            {headerName: "工程经济指标类别", headerWidth: 120, dataCode: "economicType", hAlign: "center", dataType: "String",cellType:'comboBox',options:[],editable:true,maxDropDownItems:10},
+            {headerName: "工程量指标类别", headerWidth: 150, dataCode: "quantityIndexType", hAlign: "center", dataType: "String",cellType:'comboBox',options:[],editable:true,maxDropDownItems:10},
+            {headerName: "工程量指标单位", headerWidth: 150, dataCode: "quantityIndexUnit", hAlign: "center", dataType: "String"},
+            {headerName: "单位转换系数", headerWidth: 150, dataCode: "quantityIndexCoe", hAlign: "center", dataType: "String",validator:"number"}
+        ],
+        view: {
+            lockColumns: ["code","name","unit","quantity","unitFee","totalFee","quantityIndexUnit"]
+        }
+    },
+    engineerInfoDatas:[],
+    engineerFeatureDatas:[],
+    materialDatas:[],
+    ecoQuantityDatas:[],
+    initSpread:function () {
+        if(!this.spread){
+            this.spread = SheetDataHelper.createNewSpread($("#indexSpread")[0],8);
+            sheetCommonObj.spreadDefaultStyle(this.spread);
+            this.initEngineerInfoSheet();
+            this.initEngineerFeatureSheet();
+            this.initEngineerCostSheet();
+            this.initMainMaterialSheet();
+            this.initEconomicSheet();
+            this.initQuantitySheet();
+            this.initEcoQuantitySheet();
+            this.initMaterialSheet();
+        }
+       // disableRightMenu("glj_from_sheet",this.spread);
+        if(projectReadOnly){
+            disableSpread(this.spread);
+        }
+        this.spread.refresh();
+    },
+    initEngineerInfoSheet:function () {
+        let sheet = this.spread.getSheet(0);
+        sheetCommonObj.initSheet(sheet,this.engineerInfoSetting,30);
+        sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onSelectionChange);
+        sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onEngineerInfoValueChange);
+        sheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onEngineerInfoRangeChange);
+        sheet.name('engineerInfo');
+        //sheet.setRowHeight(0, 36, 1);
+    },
+    initEngineerFeatureSheet:function () {
+        let sheet = this.spread.getSheet(1);
+        this.engineerFeatureDatas = getDatas();
+        sheetCommonObj.initSheet(sheet,this.engineerFeatureSetting,1);
+        sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.oEngineerFeatureValueChange);
+        sheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onEngineerFeatureRangeChange); //
+        sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onSelectionChange);
+        sheet.setRowCount(this.engineerFeatureDatas.length);
+        function getDatas() {
+            let datas = [];
+            if(projectObj.project.property.engineerFeatures){
+                for(let f of projectObj.project.property.engineerFeatures){
+                    let tem = {
+                        ID:f.ID,
+                        name:f.name,
+                        value:f.value,
+                        ParentID:f.ParentID,
+                        cellType:f.cellType,
+                        options:f.options,
+                        required:f.required,
+                        collapsed:false
+                    };
+                    if(f.required == true) tem.foreColor = "#ff2a23";
+                    datas.push(tem);
+                }
+            }
+            return datas;
+        }
+    },
+    initEngineerCostSheet:function () {
+        let sheet = this.spread.getSheet(2);
+        sheetCommonObj.initSheet(sheet,this.engineerCostSetting,30);
+        sheet.name('engineerCost');
+        //sheet.setRowHeight(0, 36, 1);
+    },
+    initMainMaterialSheet:function () {
+        let sheet = this.spread.getSheet(3);
+        this.setHeaderUnit(this.mainMaterialSetting,"unitIndex");
+        sheetCommonObj.initSheet(sheet,this.mainMaterialSetting,30);
+        sheet.name('mainMaterial');
+        //sheet.setRowHeight(0, 36, 1);
+    },
+    initEconomicSheet:function () {
+        let sheet = this.spread.getSheet(4);
+        sheetCommonObj.initSheet(sheet,this.economicSetting,30);
+        sheet.name('economic');
+        //sheet.setRowHeight(0, 36, 1);
+    },
+    initQuantitySheet:function () {
+        let sheet = this.spread.getSheet(5);
+        this.setHeaderUnit(this.quantitySetting,"quantity");
+        sheetCommonObj.initSheet(sheet,this.quantitySetting,30);
+        sheet.name('quantity');
+    },
+    initEcoQuantitySheet:function () {
+        let sheet = this.spread.getSheet(6);
+        this.setComboOptions(projectObj.project.property.economics,this.ecoQuantitySetting,"economicType");
+        this.setComboOptions(projectObj.project.property.mainQuantities,this.ecoQuantitySetting,"quantityIndexType");
+        sheetCommonObj.initSheet(sheet,this.ecoQuantitySetting,1);
+        sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onEcoQuantityValueChange);
+        sheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onEcoQuantityRangeChange);
+        sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onSelectionChange);
+        sheet.name('ecoQuantity');
+    },
+    initMaterialSheet:function () {
+        let sheet = this.spread.getSheet(7);
+        this.setComboOptions(projectObj.project.property.materials,this.materialSetting,"materialIndexType");
+        sheetCommonObj.initSheet(sheet,this.materialSetting,30);
+        sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onSelectionChange);
+        sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onMaterialChange);
+        sheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMaterialRangeChange);
+        sheet.name('material');
+
+    },
+    showDatas:function(){
+        let me = indexObj;
+        if(me.nav_text == "工程信息指标") me.showEngineerInfo();
+        if(me.nav_text == "工程特征指标") me.showEngineerFeature();
+        if(me.nav_text == "工程造价指标") me.showEngineerCost();
+        if(me.nav_text == "主要工料指标") me.showMainMaterial();
+        if(me.nav_text == "主要经济指标") me.showEconomic();
+        if(me.nav_text == "主要工程量指标") me.showQuantity();
+        if(me.nav_text == "设置主要经济、工程量指标") me.showEcoQuantity();
+        if(me.nav_text == "设置主要工料指标") me.showMaterial();
+
+    },
+    showEngineerInfo:function () {
+        this.spread.setActiveSheetIndex(0);
+        let sheet = this.spread.getActiveSheet();
+        this.engineerInfoDatas = getEngineerInfoData();
+        sheetCommonObj.showData(sheet, this.engineerInfoSetting,this.engineerInfoDatas);
+        sheet.setRowCount(this.engineerInfoDatas.length);
+        function getEngineerInfoData() {
+            let datas = [];
+            if(projectObj.project.property.engineerInfos){
+                for(let info of projectObj.project.property.engineerInfos){
+                    let d = {
+                        dispName:info.dispName,
+                        key:info.key,
+                        value:info.value,
+                        options:info.options,
+                        cellType:info.cellType
+                    };
+                    if(info.cellType)d.dateCol = 1;
+                    datas.push(d);
+                }
+            }
+            return datas;
+        }
+    },
+    showEngineerFeature:function () {
+        this.spread.setActiveSheetIndex(1);
+        let sheet = this.spread.getActiveSheet();
+        refreshValue();
+        this.setRowCountAndLock(sheet,this.engineerFeatureDatas);
+        sheetCommonObj.showTreeData(sheet, this.engineerFeatureSetting,this.engineerFeatureDatas);
+        function refreshValue() {
+            let map = projectObj.project.property.engineerFeatures?_.indexBy(projectObj.project.property.engineerFeatures,'ID'):{};
+            for(let f of indexObj.engineerFeatureDatas){
+                if(map[f.ID]) f.value = map[f.ID].value;
+            }
+        }
+    },
+    showEngineerCost:function () {
+        this.spread.setActiveSheetIndex(2);
+        let sheet = this.spread.getActiveSheet();
+        let costDatas = getEngineerCostData();
+        sheetCommonObj.showData(sheet, this.engineerCostSetting,costDatas);
+        sheet.setRowCount(costDatas.length);
+        function getEngineerCostData() {
+            let datas = [];
+            let priceIndex = exportUtil.setEngineerPriceIndex({property:projectObj.project.property},{bills:projectObj.project.Bills.datas});
+            for(let c of priceIndex.children){
+                let tem = {
+                    name:c.name,
+                    cost:parseFloat(c.attrs[0].value),
+                    unitCost:parseFloat(c.attrs[1].value),
+                    per:parseFloat(c.attrs[2].value)
+                }
+                datas.push(tem);
+            }
+            return datas;
+        }
+    },
+    showMainMaterial:function(){
+        this.spread.setActiveSheetIndex(3);
+        let property = projectObj.project.property;
+        let sheet = this.spread.getActiveSheet();
+        let mainDatas = this.getMainMaterialDatas(property.materials,projectObj.project.projectGLJ.datas,property.calcOptions,property.decimal,false,_,scMathUtil);
+        sheetCommonObj.showData(sheet, this.mainMaterialSetting,mainDatas);
+        sheet.setRowCount(mainDatas.length);
+    },
+    showEconomic:function () {
+        this.spread.setActiveSheetIndex(4);
+        let sheet = this.spread.getActiveSheet();
+        let economicDatas = this.getEconomicDatas(projectObj.project.property.economics,projectObj.project.Bills.datas);
+        sheetCommonObj.showData(sheet, this.economicSetting,economicDatas);
+        sheet.setRowCount(economicDatas.length);
+    },
+    showQuantity:function () {
+        this.spread.setActiveSheetIndex(5);
+        let sheet = this.spread.getActiveSheet();
+        let quantityDatas = this.getQuantityDatas(projectObj.project.property.mainQuantities,projectObj.project.Bills.datas);
+        sheetCommonObj.showData(sheet, this.quantitySetting,quantityDatas);
+        sheet.setRowCount(quantityDatas.length);
+    },
+    getQuantityDatas:function (mainQuantities,billsList) {
+        let datas = [];
+        let [bills,totalFee] = exportUtil.getIndexBills(billsList);
+        let billsGroup = _.groupBy(bills,'quantityIndexType');
+        if(!mainQuantities) return datas;
+        for(let m of mainQuantities){
+            let tem = {
+                name : m.name,
+                quantityIndexUnit:m.unit,
+                quantity:0
+            };
+            if(billsGroup[m.name]) setQuantities(billsGroup[m.name],tem);
+
+            datas.push(tem);
+        }
+
+        function setQuantities(items,data) {
+            let quantity = 0;
+            for (let i of items){
+                let coe = i.quantityIndexCoe && i.quantityIndexCoe!=""?parseFloat(i.quantityIndexCoe):0;
+                i.quantity = scMathUtil.roundForObj(parseFloat(i.quantity)*coe,getDecimal("process"));
+                quantity = scMathUtil.roundForObj(quantity +  i.quantity,getDecimal("process"));
+            }
+            data.quantity = exportUtil.calUnitWidthCoe(quantity);
+        }     
+        
+        return datas;
+    },
+    getEconomicDatas:function (economics,billsList) {
+        let datas = [];
+        let [bills,totalFee] = exportUtil.getIndexBills(billsList);
+        let billsGroup = _.groupBy(bills,'economicType');
+        if(!economics) return datas;
+        for(let e of economics){
+            let tem = {
+                name:e.name,
+                cost:0,
+                unitCost:0,
+                per:0
+            };
+            if(billsGroup[e.name]) setEconomics(billsGroup[e.name],totalFee,tem);
+            datas.push(tem);
+        }
+        function setEconomics(items,engineerCost,data) {
+            let cost = 0;
+            let priceDe = getDecimal("bills.totalPrice");
+            for(let i of items){
+                i.totalFee =  scMathUtil.roundForObj(i.totalFee,priceDe);
+                cost = scMathUtil.roundForObj(cost + i.totalFee,getDecimal("process"));
+            }
+            data.cost = scMathUtil.roundForObj(cost,priceDe);
+            data.unitCost = exportUtil.calUnitWidthCoe(data.cost,true);//noNeedCoe = true 这里不需要乘以系数
+            data.per = engineerCost?scMathUtil.roundForObj(data.cost/engineerCost * 100,2):0;
+        }
+
+        return datas;
+    },
+
+    getMainMaterialDatas:function (materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil) {
+        let datas = [];
+        let materialGroup = _.groupBy(projectGLJData.gljList,'materialIndexType');
+        if(!materials) return datas;
+        for(let m of materials){
+            let tem = {
+                name:m.name,
+                unit:m.unit,
+                unitPrice:0,
+                quantity:0,
+                unitIndex:0
+            };
+            if(materialGroup[m.name]) setMainMaterial(materialGroup[m.name],tem);
+            datas.push(tem);
+        }
+
+        function setMainMaterial(gljs,data) {
+            let quantity = 0 ,unitPrice=0;
+            for(let g of gljs){
+                if(!g.quantity || g.quantity=="") continue;
+                let marketPrice = gljUtil.getMarketPrice(g,projectGLJData,calcOptions,decimalObj,false,_,scMathUtil); // gljOprObj.setGLJPrice(tem,g);
+                let materialIndexCoe = g.materialIndexCoe?scMathUtil.roundForObj(g.materialIndexCoe,getDecimal("process")):0;
+                let t_quantity = scMathUtil.roundForObj(g.quantity * materialIndexCoe,getDecimal("process"));
+                quantity = scMathUtil.roundForObj(t_quantity + quantity,getDecimal("process"));
+                let temPrice = scMathUtil.roundForObj(g.quantity * marketPrice,getDecimal("process"));
+                unitPrice = scMathUtil.roundForObj(temPrice + unitPrice,getDecimal("process"));
+            }
+            data.quantity = scMathUtil.roundForObj(quantity,2);
+            if(data.quantity) data.unitPrice = scMathUtil.roundForObj(unitPrice/data.quantity,2);
+            data.unitIndex = exportUtil.calUnitWidthCoe(data.quantity);
+        }
+
+        return datas;
+    },
+    showEcoQuantity:function () {
+        let parentMap = {};
+        this.spread.setActiveSheetIndex(6);
+        let sheet = this.spread.getActiveSheet();
+        let sel = sheet.getSelections()[0];
+        let oldData = sel.row<this.ecoQuantityDatas.length?this.ecoQuantityDatas[sel.row]:null;
+        this.ecoQuantityDatas = this.getIndexBillsData(parentMap);
+        sheet.setRowCount(0);
+        this.setRowCountAndLock(sheet,this.ecoQuantityDatas);
+        sheetCommonObj.showTreeData(sheet, this.ecoQuantitySetting,this.ecoQuantityDatas);
+        sel.row = oldData?_.findIndex(this.ecoQuantityDatas,{'ID':oldData.ID}):0;
+        sheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+
+        for(let row =0 ;row < this.ecoQuantityDatas.length;row ++){//锁定父清单
+            if(parentMap[this.ecoQuantityDatas[row].ID]) sheet.getRange(row,-1 -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+        }
+    },
+    getIndexBillsData:function (parentMap,old) {
+        let datas = [],allNodes=[];
+        let controller = projectObj.mainController, project = projectObj.project;
+        let  FBFX = project.Bills.getFBFXNode(controller);
+        let IDMap = _.indexBy(this.ecoQuantityDatas,"ID");
+        if(FBFX){
+            allNodes.push(FBFX);
+            controller.tree.getAllSubNode(FBFX.source,allNodes);
+        }
+        let org = project.Bills.getOrgNode();
+        let mNode = project.Bills.getMeasureNode(controller);
+        if(mNode){
+            allNodes.push(mNode);
+            controller.tree.getAllSubNode(mNode.source,allNodes,org?org.data.ID:null);
+        }
+        for(let a of allNodes){
+            let d = a.data;
+            let tem = {
+                ID:d.ID,
+                ParentID:d.ParentID,
+                code:d.code,
+                name:d.name,
+                unit:d.unit,
+                quantity:d.quantity,
+                totalFee:d.feesIndex && d.feesIndex.common && d.feesIndex.common.totalFee?d.feesIndex.common.totalFee:0,
+                unitFee:d.feesIndex && d.feesIndex.common && d.feesIndex.common.unitFee?d.feesIndex.common.unitFee:0,
+                economicType:d.economicType,
+                quantityIndexType:d.quantityIndexType,
+                quantityIndexUnit:d.quantityIndexUnit,
+                quantityIndexCoe:d.quantityIndexCoe,
+                collapsed:IDMap[d.ID]?IDMap[d.ID].collapsed:false
+            };
+            parentMap[d.ParentID] = tem;
+            datas.push(tem);
+        }
+        for(let td of datas){
+            if(parentMap[td.ID]){
+                td.economicType = "";
+                td.quantityIndexType = "";
+                td.quantityIndexUnit = "";
+                td.quantityIndexCoe = "";
+            }
+        }
+        return datas;
+
+    },
+    showMaterial:function(){
+        this.spread.setActiveSheetIndex(7);
+        let sheet = this.spread.getActiveSheet();
+        let sel = sheet.getSelections()[0];
+        let oldData = sel.row<this.materialDatas.length?this.materialDatas[sel.row]:null;
+        this.materialDatas = getMaterialData();
+        sheetCommonObj.showData(sheet, this.materialSetting,this.materialDatas );
+        sel.row = oldData?_.findIndex(this.materialDatas,{'id':oldData.id}):0;
+        sheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+        this.setRowCountAndLock(sheet,this.materialDatas);
+        function getMaterialData() {
+            let datas = [];
+            let gljList = projectObj.project.projectGLJ.datas.gljList;
+            gljList = _.filter(gljList,function(item){
+                return item.quantity !== 0 && item.quantity !== '0'
+            });
+            gljList = sortProjectGLJ(gljList);
+            for(let glj of gljList){
+                let tem = {
+                    id:glj.id,
+                    code:glj.code,
+                    name:glj.name,
+                    specs:glj.specs,
+                    unit:glj.unit,
+                    type:glj.type,
+                    quantity:glj.quantity,
+                    materialIndexType:glj.materialIndexType,
+                    materialIndexUnit:glj.materialIndexUnit,
+                    materialIndexCoe:glj.materialIndexCoe
+                };
+                gljOprObj.setGLJPrice(tem,glj);
+                tem.totalPrice = scMathUtil.roundForObj(tem.marketPrice * glj.quantity,getDecimal("glj.unitPrice"))
+                datas.push(tem);
+            }
+            return datas;
+        }
+    },
+    setRowCountAndLock:function (sheet,datas) {
+        let rowCount = datas.length > 0 ?datas.length+11:0;
+        sheet.setRowCount(rowCount);
+        sheet.getRange(datas.length, -1, 11, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);//锁定空行
+    },
+    setComboOptions:function (property,setting,field) {
+        if(!property) return;
+        let options = [""];
+        for(let p of property){
+            options.push(p.name);
+        }
+        let h = _.find(setting.header,{dataCode:field});
+        if(h) h.options = options;
+    },
+    onSelectionChange:function (sender, args) {
+        args.sheet.repaint();
+    },
+    onEcoQuantityValueChange:function (sender,info) {
+        let value = info.newValue;
+        let dataCode = indexObj.ecoQuantitySetting.header[info.col].dataCode;
+        if(!gljUtil.isDef(info.newValue)){
+            return;
+        }
+        if (value&&!sheetCommonObj.checkData(info.col,indexObj.ecoQuantitySetting, value)) {
+            alert('输入的数据类型不对,请重新输入!');
+            return indexObj.showDatas();
+        }
+        let recode = indexObj.ecoQuantityDatas[info.row];
+        let data = indexObj.getEcoQuantityUpdateData(recode,dataCode,value);
+        if(data == null)  return indexObj.showDatas();
+        projectObj.project.updateNodesAndRefresh([data],indexObj.showDatas)
+    },
+    onEngineerInfoValueChange:function (sender,info) {
+        let value = info.newValue;
+        value = indexObj.valueChecking(indexObj.engineerInfoDatas[info.row],value,info.sheet);
+        let infos = projectObj.project.property.engineerInfos;
+        let data = indexObj.getNewPropertyData([{row:info.row,value:value}],infos);
+        if(!data) return indexObj.showDatas();
+        indexObj.updateProjectProperty(data,"engineerInfos");
+    },
+    valueChecking:function (recode,value,sheet) {
+        if(recode && recode.cellType == "date"){//日期类型要做个转换
+            sheet.tag(value);
+            let data = sheet.tag();
+            value =  formatDate(new Date(data), 'yyyy-MM-dd');
+        }
+         //to do other checking
+        return value
+    },
+
+
+    oEngineerFeatureValueChange:function(sender,info){
+        let value = info.newValue;
+        let features = projectObj.project.property.engineerFeatures;
+        let data = indexObj.getNewPropertyData([{row:info.row,value:value}],features);
+        if(!data) return indexObj.showDatas();
+        indexObj.updateProjectProperty(data,"engineerFeatures");
+    },
+    onEngineerFeatureRangeChange:function (sender,info) {
+        let features = projectObj.project.property.engineerFeatures;
+        let datas = [];
+        for(let c of info.changedCells){
+            let value =  info.sheet.getCell(c.row, c.col).text();
+            datas.push({row:c.row,value:value})
+        }
+        let data = indexObj.getNewPropertyData(datas,features);
+        if(!data) return indexObj.showDatas();
+        indexObj.updateProjectProperty(data,"engineerFeatures");
+    },
+    onEngineerInfoRangeChange:function (sender,info) {
+        let infos = projectObj.project.property.engineerInfos;
+        let datas = [];
+        for(let c of info.changedCells){
+            let value =  info.sheet.getCell(c.row, c.col).text();
+            datas.push({row:c.row,value:value})
+        }
+        let data = indexObj.getNewPropertyData(datas,infos);
+        if(!data) return indexObj.showDatas();
+        indexObj.updateProjectProperty(data,"engineerInfos");
+
+    },
+    updateProjectProperty: function(datas,field){
+        let pfield = "property."+field;
+        let tem ={
+            type:'project',
+            data:{ID:projectObj.project.ID()}
+        };
+        tem.data[pfield] = datas;    
+             
+        projectObj.project.updateNodes([tem],function () {
+            projectObj.project.property[field] = datas;
+            indexObj.showDatas();
+        })
+
+    },
+    getNewPropertyData:function (datas,property) {
+        if(!property) return null;
+        property = _.cloneDeep(property);
+        for(let d of datas){
+            if(property[d.row])property[d.row].value = d.value;
+        }
+        return property;
+    },
+
+    onMaterialChange:function (sender,info) {
+        let value = info.newValue,updateMap = {};
+        let dataCode = indexObj.materialSetting.header[info.col].dataCode;
+        if(!gljUtil.isDef(info.newValue)){
+            return;
+        }
+        if (value&&!sheetCommonObj.checkData(info.col,indexObj.materialSetting, value)) {
+            alert('输入的数据类型不对,请重新输入!');
+            return indexObj.showDatas();
+        }
+        let recode = indexObj.materialDatas[info.row];
+        let data = indexObj.getMaterialUpdateData(recode,dataCode,value);
+        if(!data) return indexObj.showDatas() ;
+        updateMap[recode.id] = data;
+        projectObj.project.projectGLJ.batchUpdateGLJProperty(updateMap,indexObj.showDatas);
+
+    },
+    onEcoQuantityRangeChange:function (sender,info) {
+        let nodes = [];
+        for(let c of info.changedCells){
+            let dataCode = indexObj.ecoQuantitySetting.header[c.col].dataCode;
+            let value= info.sheet.getCell(c.row, c.col).text();
+            if (value&&!sheetCommonObj.checkData(c.col,indexObj.ecoQuantitySetting, value)) {
+                alert('输入的数据类型不对,请重新输入!');
+                return indexObj.showDatas();
+            }
+            let recode = indexObj.ecoQuantityDatas[c.row];
+            let data = indexObj.getEcoQuantityUpdateData(recode,dataCode,value);
+            if(data) nodes.push(data);
+        }
+        if(_.isEmpty(nodes)) return indexObj.showDatas();
+        projectObj.project.updateNodesAndRefresh(nodes,indexObj.showDatas)
+    },
+    onMaterialRangeChange:function (sender,info) {
+        let updateMap = {};
+        for(let c of info.changedCells){
+            let value=  info.sheet.getCell(c.row, c.col).text();
+            let dataCode = indexObj.materialSetting.header[c.col].dataCode;
+            let recode = indexObj.materialDatas[c.row];
+            if (value&&!sheetCommonObj.checkData(c.col,indexObj.materialSetting, value)) {
+                alert('输入的数据类型不对,请重新输入!');
+                return indexObj.showDatas();
+            }
+            let tem = indexObj.getMaterialUpdateData(recode,dataCode,value);
+            if(tem) updateMap[recode.id] = tem;
+        }
+        if(_.isEmpty(updateMap)) return indexObj.showDatas();
+        projectObj.project.projectGLJ.batchUpdateGLJProperty(updateMap,indexObj.showDatas);
+    },
+    getEcoQuantityUpdateData:function (recode,dataCode,newValue) {
+        let tem = {
+            type:ModuleNames.bills,
+            data:{ID:recode.ID}
+        };
+        tem.data[dataCode] = newValue;
+        if(!recode) return null;
+        if(dataCode == "quantityIndexType"){
+            if(newValue == ""){
+                tem.data["quantityIndexUnit"] = "";
+                tem.data["quantityIndexCoe"] = null;
+            }else {
+                let mainQuantities = projectObj.project.property.mainQuantities;
+                if (!mainQuantities) return null;
+                let m =  _.find(mainQuantities,{name:newValue});
+                if(!m) return null;
+                tem.data["quantityIndexUnit"] = m.unit;
+                tem.data["quantityIndexCoe"] = recode.unit == m.unit? 1:null;
+            }
+
+        }
+        if(dataCode == "economicType"){//这里就主要查找输入是否是下列选项中的一个,值已经在上面设置了
+            if(newValue != ""){
+                let economics = projectObj.project.property.economics;
+                if (!economics) return null;
+                let m =  _.find(economics,{name:newValue});
+                if(!m) return null;
+            }
+        }
+        return tem;
+
+    },
+    getMaterialUpdateData:function (recode,dataCode,newValue) {
+        let data = {};
+        data[dataCode] = newValue;
+        if(dataCode == "materialIndexType"){
+            if(newValue == ""){
+                data["materialIndexUnit"] = "";
+                data["materialIndexCoe"] =  null;
+            }else {
+                let materials = projectObj.project.property.materials;
+                if (!materials) return null;
+                if(!recode) return null;
+                let m =  _.find(materials,{name:newValue});
+                if(!m) return null;
+                data["materialIndexUnit"] = m.unit;
+                data["materialIndexCoe"] =  recode.unit == m.unit ?1: null;
+                if(recode.name == "水泥" && m.name == "水泥")  data["materialIndexCoe"] = 0.001;
+            }
+
+        }
+        return data
+    },
+    getIndexUnit:function () {
+        let features  = projectObj.project.property.engineerFeatures;
+        if(features){
+            for(let f of features){
+                if(f.index == true && f.indexUnit && f.indexUnit!="") return f.indexUnit;
+            }
+        }
+        return null;
+    },
+    setHeaderUnit:function (setting,dataCode) {
+      let header = _.find(setting.header,{dataCode:dataCode});
+      let unit = this.getIndexUnit();
+      if(!unit || !header )return;
+      header.headerName +=`(${unit})`
+    }
+};
+
+
+$(function () {
+    $("#index_nav").on("click","ul li a",function(e){
+        let children = $('#index_nav a');
+        for(let c of children){
+            $(c).removeClass('active');
+        }
+        $(this).addClass('active');
+        indexObj.nav_text = $(this).text();
+        indexObj.showDatas();
+    });
+
+    $('#tab_index').on('shown.bs.tab', function (e) {
+        indexObj.initSpread();
+        indexObj.showDatas();
+    });
+});
+
+function onResize() {
+    if(indexObj.spread) indexObj.spread.refresh();
+}

+ 14 - 1
web/building_saas/main/js/views/main_tree_col.js

@@ -69,6 +69,13 @@ let MainTreeCol = {
                 if (rate) return rate.rate;
             }
             return node.data.feeRate;
+        },
+        maxPrice:function (node) {
+            if(node.data.outPutMaxPrice == true){
+                if(node.data.maxPrice === null&&node.data.feesIndex &&node.data.feesIndex.common) return node.data.feesIndex.common.unitFee?node.data.feesIndex.common.unitFee:"";
+                return node.data.maxPrice?node.data.maxPrice:"";
+            }
+            return "";
         }
     },
     readOnly: {
@@ -130,7 +137,6 @@ let MainTreeCol = {
             }
             return false;
         },
-
         //根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
             function isDef(v) {
@@ -264,6 +270,10 @@ let MainTreeCol = {
                 }
             }
             return true;
+        },
+        maxPrice:function (node) {
+            if($("#fileKind").val() == '1') return true;//对于投标项目只读
+            return   node.data.outPutMaxPrice!==true;
         }
     },
     cellType: {
@@ -357,6 +367,9 @@ let MainTreeCol = {
         },
         mainBills:function (node) {
             if(MainTreeCol.mainBillsEnable(node)) return sheetCommonObj.getCheckBox(true);
+        },
+        outPutMaxPrice:function (node) {
+            if(MainTreeCol.mainBillsEnable(node) && $("#fileKind").val() != '1') return sheetCommonObj.getCheckBox(true);
         }
     },
     mainBillsEnable:function (node) {

+ 106 - 31
web/building_saas/main/js/views/material_adjust_view.js

@@ -14,10 +14,10 @@ let materialAdjustObj = {
             {headerName: "规格型号", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell'},
             {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
             {headerName: "数量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity'},
-            {headerName: "风险系数", headerWidth: 90, dataCode: "riskCoe", hAlign: "right", dataType: "Number",validator:"number"},
+            {headerName: "风险系数%", headerWidth: 60, dataCode: "riskCoe", hAlign: "right", dataType: "Number",validator:"number"},
             {headerName: "基准单价", headerWidth: 70, dataCode: "standardPrice", hAlign: "right", dataType: "Number",validator:"number"},
             {headerName: "投标单价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},
-            {headerName: "合价", headerWidth: 70, dataCode: "totalPrice", hAlign: "right", dataType: "Number",validator:"number"},
+            {headerName: "合价", headerWidth: 90, dataCode: "totalPrice", hAlign: "right", dataType: "Number",validator:"number",decimalField:'bills.totalPrice'},
             {headerName: "产地", headerWidth: 80, dataCode: "originPlace", hAlign: "left", dataType: "String"},
             {headerName: "厂家", headerWidth: 80, dataCode: "vender", hAlign: "left", dataType: "String"},
             {headerName: "供货方式", headerWidth: 70, dataCode: "supply", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:supplyComboMap},
@@ -32,11 +32,11 @@ let materialAdjustObj = {
             {headerName: "规格型号", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell'},
             {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
             {headerName: "变值权重B", headerWidth: 90, dataCode: "varWeight", hAlign: "right", dataType: "Number",validator:"number"},
-            {headerName: "基本价格指数FO", headerWidth: 70, dataCode: "FO", hAlign: "right", dataType: "Number",validator:"number"},
-            {headerName: "现行价格指数FI", headerWidth: 70, dataCode: "FI", hAlign: "right", dataType: "Number",validator:"number"},
+            {headerName: "基本价格指数F0", headerWidth: 70, dataCode: "FO", hAlign: "right", dataType: "Number",validator:"number"},
+            {headerName: "现行价格指数Ft", headerWidth: 70, dataCode: "FI", hAlign: "right", dataType: "Number",validator:"number"},
             {headerName: "数量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity'},
             {headerName: "单价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},
-            {headerName: "合价", headerWidth: 70, dataCode: "totalPrice", hAlign: "right", dataType: "Number",validator:"number"},
+            {headerName: "合价", headerWidth: 90, dataCode: "totalPrice", hAlign: "right", dataType: "Number",validator:"number",decimalField:'bills.totalPrice'},
             {headerName: "产地", headerWidth: 80, dataCode: "originPlace", hAlign: "left", dataType: "String"},
             {headerName: "厂家", headerWidth: 80, dataCode: "vender", hAlign: "left", dataType: "String"},
             {headerName: "供货方式", headerWidth: 70, dataCode: "supply", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:supplyComboMap},
@@ -45,7 +45,13 @@ let materialAdjustObj = {
         view:{ lockColumns: ["code","name","specs","unit","quantity","totalPrice","originPlace","vender","supply","remark"]}
     },
     refreshSheetDatas:function () {
-        $("#adjustType").val() == "priceInfo" ? materialAdjustObj.showPriceInfoDatas():materialAdjustObj.showPriceCoeDatas();
+        //读项目属性的值,若没有则默认为造价信息差额调整法
+        let adjustType = $('#adjustType').val();
+        if (adjustType === 'priceInfo') {
+            materialAdjustObj.showPriceInfoDatas();
+        } else {
+            materialAdjustObj.showPriceCoeDatas();
+        }
         //let sheetIndex = $("#adjustType").val()
     },
     initSpread:function () {
@@ -67,16 +73,50 @@ let materialAdjustObj = {
         this.priceInfoSheet = this.spread.getSheet(0);
         sheetCommonObj.initSheet(this.priceInfoSheet,this.priceInfoSetting,30);
         this.priceInfoSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange);
+        this.priceInfoSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onSheetRangeChange);
         this.priceInfoSheet.name('priceInfoSheet');
-        this.priceInfoSheet.setRowHeight(0, 45, 1);
+        this.priceInfoSheet.setRowHeight(0, 36, 1);
     },
     initPriceCoeSheet:function () {
         this.priceCoeSheet = this.spread.getSheet(1);
         sheetCommonObj.initSheet(this.priceCoeSheet,this.priceCoeSetting,30);
         this.priceCoeSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange);
+        this.priceCoeSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onSheetRangeChange);
         this.priceCoeSheet.name('priceCoeSheet');
-        this.priceCoeSheet.setRowHeight(0, 45, 1);
+        this.priceCoeSheet.setRowHeight(0, 36, 1);
+    },
+    onSheetRangeChange:function (a,args) {
+        let me = materialAdjustObj,updateMap = {};
+        let projectGLJ = projectObj.project.projectGLJ;
+        let setting = $("#adjustType").val() == "priceInfo"?me.priceInfoSetting:me.priceCoeSetting;
+        let datas = $("#adjustType").val() == "priceInfo"?me.priceInfoDatas:me.priceCoeDatas;
+        for(let c of args.changedCells){
+            let dataCode = setting.header[c.col].dataCode;
+            let value= args.sheet.getCell(c.row, c.col).text();
+            if (value&&!sheetCommonObj.checkData(c.col,setting,value)) {
+                alert('输入的数据类型不对,请重新输入!');
+                me.refreshSheetDatas();
+                return ;
+            }
+            let recode = datas[c.row];
+            if(dataCode=='marketPrice'){
+                let editField ="market_price";
+                projectGLJ.updatePrice(recode,editField,value,'pg',me.refreshSheetDatas);
+            }else {
+                let tem = {};
+                if(value) value = scMathUtil.roundForObj(value,getDecimal("process"));
+                if(value == recode[dataCode]) continue;
+                tem[dataCode] = value;
+                updateMap[recode.id] = tem;
+            }
+        }
+        if( _.isEmpty(updateMap)) return;
+        projectGLJ.batchUpdateGLJProperty(updateMap,function () {
+            me.refreshSheetDatas();
+        });
+
     },
+
     onSheetValueChange:function (a,args) {
         let me = materialAdjustObj,row = args.row, col = args.col;
         let projectGLJ = projectObj.project.projectGLJ;
@@ -101,19 +141,26 @@ let materialAdjustObj = {
             projectGLJ.updatePrice(recode,editField,value,'pg',me.refreshSheetDatas);
             return;
         }
-        value = scMathUtil.roundForObj(value,getDecimal("process"));
+        if(value) value = scMathUtil.roundForObj(value,getDecimal("process"));
+        if(value == null) value="";
         let updateData = {id: recode.id, field: dataCode, value: value+""};
         projectGLJ.pGljUpdate(updateData,me.refreshSheetDatas);
 
     },
-    deleteAdjust:function (row) {
-        let me = this;
+    deleteAdjust:function () {
+        let me = this,updateMap={};
         let projectGLJ = projectObj.project.projectGLJ;
-        let field =  $("#adjustType").val() == "priceInfo"?"is_info_adjust":"is_coe_adjust";
         let datas = $("#adjustType").val() == "priceInfo"?me.priceInfoDatas:me.priceCoeDatas;
-        let recode = datas[row];
-        let updateData = {id: recode.id, field: field, value: 0};
-        projectGLJ.pGljUpdate(updateData,me.refreshSheetDatas);
+        let sels = this.spread.getActiveSheet().getSelections();
+        let select =  sels.length > 0? sels[0]:null;
+        if(!select) return;
+        for(let i =0;i<select.rowCount;i++){
+            let recode = datas[select.row+i];
+            if(recode) updateMap[recode.id] = {is_info_adjust:0,is_coe_adjust:0};
+        }
+        if( _.isEmpty(updateMap)) return;
+        projectGLJ.batchUpdateGLJProperty(updateMap,materialAdjustObj.refreshSheetDatas);
+
     },
     showPriceInfoDatas:function () {
         this.spread.setActiveSheetIndex(0);
@@ -127,9 +174,9 @@ let materialAdjustObj = {
         sheetCommonObj.showData(this.priceCoeSheet, this.priceCoeSetting,this.priceCoeDatas);
         this.priceCoeSheet.setRowCount(this.priceCoeDatas.length);
     },
-    getPirceInfoDatas:function(){
+    getPirceInfoDatas:function(projectGLJList){
         let datas = [];
-        let gljList = this.filterAdjustGlj();
+        let gljList = this.filterAdjustGlj(projectGLJList, 'is_info_adjust');
         gljList = sortProjectGLJ(gljList);
         for(let glj of gljList){
             datas.push(getInfoObject(glj));
@@ -143,18 +190,19 @@ let materialAdjustObj = {
             return data;
         }
     },
-    filterAdjustGlj:function () {
-        let gljList = projectObj.project.projectGLJ.datas.gljList;
-        let field =  $("#adjustType").val() == "priceInfo"?"is_info_adjust":"is_coe_adjust";
+    filterAdjustGlj:function (projectGLJList, field) {
+        let gljList = projectGLJList?projectGLJList:projectObj.project.projectGLJ.datas.gljList;
         return _.filter(gljList,function (item) {
             return item.quantity !== 0 && item.quantity !== '0' && item[field] ===1
         });
     },
-    getPriceCoeDatas:function () {
+    getPriceCoeDatas:function (projectGLJList,totalFee) {
         let datas = [];
-        let node =  projectObj.project.Bills.getEngineeringCostNode(projectObj.mainController);
-        let totalFee = node && node.data.feesIndex && node.data.feesIndex.common?node.data.feesIndex.common.totalFee:0;
-        let gljList = this.filterAdjustGlj();
+        if(!gljUtil.isDef(totalFee)){
+            let node =  projectObj.project.Bills.getEngineeringCostNode(projectObj.mainController);
+            totalFee = node && node.data.feesIndex && node.data.feesIndex.common?node.data.feesIndex.common.totalFee:0;
+        }
+        let gljList = this.filterAdjustGlj(projectGLJList, 'is_coe_adjust');
          gljList = sortProjectGLJ(gljList);
         for(let glj of gljList){
             datas.push(getCoeObject(glj,totalFee));
@@ -200,7 +248,7 @@ let materialAdjustObj = {
                     },
                     callback: function (key, opt) {
                         let row = me.rightClickTarget.row;
-                        me.deleteAdjust(row);
+                        me.deleteAdjust();
                     }
                 }
             }
@@ -251,6 +299,7 @@ let gljFromObj={
             lockColumns: ["is_evaluate"]
         }
     },
+    checkType:"取消",//记住点击过的按钮的text
     initSpread:function () {
         if(!this.spread){
             this.spread = SheetDataHelper.createNewSpread($("#glj_from_sheet")[0]);
@@ -261,7 +310,7 @@ let gljFromObj={
         this.sheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onEditStarting);
         this.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, this.onClipboardPasting);
         this.sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onValueChanged);
-        this.sheet.setRowHeight(0, 45, 1);
+        this.sheet.setRowHeight(0, 36, 1);
         disableRightMenu("glj_from_sheet",this.spread);
     },
     onEditStarting:function (e,args) {
@@ -306,6 +355,7 @@ let gljFromObj={
         });
     },
     refreshDatas:function () {
+        this.checkByType(this.checkType);
         sheetCommonObj.showData(this.sheet, this.setting,this.datas);
         this.sheet.setRowCount(this.datas.length);
     },
@@ -337,19 +387,19 @@ let gljFromObj={
                     break;
             }
         }
-        this.refreshDatas();
+        //this.refreshDatas();
     },
     confirmSelect:function () {
         let updateMap = {};
         let adjustType =  $("#adjustType").val()
         for(let d of this.datas){
             if(d.select == 1){
-                let tem;
-                if(adjustType== "priceInfo"){
+                let tem = {is_info_adjust:1,riskCoe:"",standardPrice:d.marketPrice+"",is_coe_adjust:1,FI:"",FO:""};//现在改成添加的话,两个页面都添加,删除两个页面都删除
+             /*   if(adjustType== "priceInfo"){
                     tem = {is_info_adjust:1,riskCoe:"",standardPrice:d.marketPrice+""};
                 }else {
                     tem = {is_coe_adjust:1,FI:"",FO:""};
-                }
+                }*/
                 updateMap[d.id] = tem;
             }
         }
@@ -364,12 +414,36 @@ let gljFromObj={
 $(function () {
     $("#adjustType").change(function () {
         materialAdjustObj.refreshSheetDatas();
+        let val = $(this).val();
+        let mixDatas = {projectID: projectObj.project.projectInfo.ID, updateType: 'update',
+            properties: {'property.gljAdjustType': val},
+            options: {}, labourCoes: {}, rations: [], bills: []};
+        CommonAjax.post('/pm/api/updateMixDatas', {user_id: userID, mixDataArr: mixDatas}, function (rstData) {
+            projectObj.project.projectInfo.property.gljAdjustType = val;
+        });
     });
     $('#selectFromGLJ').on('shown.bs.modal',function(e){
+        gljFromObj.checkType="取消";
         gljFromObj.initSpread();
         gljFromObj.showDatas();
     });
     $(".glj_sel_input").change(function () {
+        let check = $(this).prop("checked");
+        if($(this).val() == 0){//勾选的是全选,其它的勾选项跟着改变
+            for(let a of $(".glj_sel_input")){
+                $(a).prop("checked",check)
+            }
+        }else {//勾选其它选项
+            let a_checked = true;
+            for(let o of $(".glj_sel_input_other")){//如果其它的有一个不勾选,则所有项也不打勾
+                if($(o).prop("checked") === false){
+                    a_checked = false;
+                    break;
+                }
+            }
+            $("#glj_sel_all").prop("checked",a_checked);
+        }
+
         gljFromObj.showDatas();
     });
 
@@ -378,7 +452,8 @@ $(function () {
     });
 
     $(".glj_sel_check_btn").click(function () {
-        gljFromObj.checkByType($(this).text())
+        gljFromObj.checkType = $(this).text();
+        gljFromObj.refreshDatas();
     })
     
     $("#glj_sel_confirm").click(function () {

+ 6 - 3
web/building_saas/main/js/views/project_glj_view.js

@@ -79,7 +79,7 @@ projectGljObject={
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onProjectGljSelectionChange);
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onProjectGljEditStarting);
         this.projectGljSheet.name('projectGljSheet');
-        this.projectGljSheet.setRowHeight(0, 45, 1);
+        this.projectGljSheet.setRowHeight(0, 36, 1);
     },
     initMixRatio:function () {
         let me = projectGljObject;
@@ -522,6 +522,8 @@ projectGljObject={
         if(me.displayType == filterType.AMAE){
             $('#material_adjust').show();
             $('#adjustType').show();
+            let adjustType = projectObj.project.projectInfo.property.gljAdjustType || 'priceInfo';
+            $('#adjustType').val(adjustType);
             $('#project-glj-main').hide();
         } else {
             $('#material_adjust').hide();
@@ -1086,10 +1088,11 @@ projectGljObject={
         });
     },
     initFilterTypeList:function () {//初始化人材机汇总工料机类型过滤列表
-        let htmlString = '';
+        let htmlString = ' <ul class="nav flex-column">';
         for(let t of this.displayTypeMap){
-            htmlString += '<li class="nav-item li_sub"><a class="nav-link" href="javascript:void(0)" id="'+t.ID+'">'+t.text+'</a></li>';
+            htmlString += '<li class="nav-item "><a class="nav-link pl-4" href="javascript:void(0)" id="'+t.ID+'">'+t.text+'</a></li>';
         }
+        htmlString += '</ul>';
         $('#ALL').after(htmlString);
     }
 };

+ 47 - 16
web/building_saas/main/js/views/project_view.js

@@ -540,6 +540,13 @@ var projectObj = {
                 project.calcProgram.calcAndSave(node);
             } else {
                 if (node.sourceType === project.Bills.getSourceType()) {
+                    if(fieldName == "maxPrice"){
+                        if(value == null){
+                            value = "";
+                        }else {
+                            value = scMathUtil.roundToString(value,getDecimal("unitPrice", node))
+                        }
+                    }
                     project.Bills.updateField(node.source, fieldName, value, false);
                 } else if (node.sourceType === project.Ration.getSourceType()) {
                     project.Ration.updateField(node.source, fieldName, value);
@@ -960,7 +967,7 @@ var projectObj = {
                     // if (col.data.field.hasSubStr("common")){
                         if (col.data.field.hasSubStr(".totalFee"))
                             col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, true);
-                        else if (col.data.field.hasSubStr(".unitFee"))
+                        else if (col.data.field.hasSubStr(".unitFee")||col.data.field.hasSubStr("maxPrice"))
                             col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true);
                     // }
 
@@ -1474,7 +1481,7 @@ var projectObj = {
                         }
                     },
                     visible:function(key, opt){//2018-11-15 新需求隐藏右键“造价计算”。
-                        return false;
+                        return true;
                     }
                 },
                 "spr4":'--------',
@@ -1734,10 +1741,9 @@ var projectObj = {
             projectObj.onIsEstimateClick(node,info);
         }else if(fieldName == "evaluationProject"){
             projectObj.onEvaluationProjectClic(node,info);
-        }else if(fieldName == "mainBills"){
-            projectObj.onMainBillsClick(node,info);
+        }else if(fieldName == "mainBills"||fieldName == "outPutMaxPrice"){
+            projectObj.onCasCadeButtonClick(node,info,fieldName);
         }
-
     },
     onEvaluationProjectClic:function (node,info) {
         let checkboxValue = info.sheet.getCell(info.row, info.col).value();
@@ -1767,7 +1773,7 @@ var projectObj = {
             projectObj.project.projectGLJ.pGljUpdate(updateData);
         }
     },
-    onMainBillsClick:function (node,info) {//清单有三种状态,true,false,null。 打勾:true, 不打勾 false 子项有打勾和不打勾的情况 null
+   /* onMainBillsClick:function (node,info) {//清单有三种状态,true,false,null。 打勾:true, 不打勾 false 子项有打勾和不打勾的情况 null
         let checkboxValue = info.sheet.getCell(info.row, info.col).value();
         let cell = info.sheet.getCell(info.row, info.col), newval = true;
         if (checkboxValue == true) {
@@ -1776,6 +1782,16 @@ var projectObj = {
             newval = true;
         }
         projectObj.project.updateMainBills(node,newval);
+    },*/
+    onCasCadeButtonClick:function (node,info,fieldName) {
+        let checkboxValue = info.sheet.getCell(info.row, info.col).value();
+        let cell = info.sheet.getCell(info.row, info.col), newval = true;
+        if (checkboxValue == true) {
+            newval = false;
+        } else {
+            newval = true;
+        }
+        projectObj.project.updateCasCadeBills(node,newval,fieldName);
     },
     onSubcontractClick:function (node) {//点击分包费checkbox
         if (node.data.isSubcontract) node.data.isSubcontract = false;
@@ -2158,6 +2174,21 @@ $('#importSpan').click(function () {
 $('#importDropDown').click(function () {
     $('[data-toggle="tooltip"]').tooltip('hide');
 });
+//导出接口下拉
+$('#exportSpan').click(function () {
+    $('[data-toggle="tooltip"]').tooltip('hide');
+    let toggle = $('#exportSpan>a').attr('data-toggle');
+    if (toggle) {
+        $('#exportSpan>a').removeAttr('data-toggle');
+    }
+    $('#exportSpan>a').dropdown('toggle');
+    setTimeout(function () {
+        $('#exportSpan>a').attr('data-toggle', 'dropdown');
+    }, 100);
+});
+$('#exportSpan>a').click(function () {
+    $('[data-toggle="tooltip"]').tooltip('hide');
+});
 $('body').click(function () {
     //点击完后隐藏子菜单
    if ($('#subDisplay').is(':visible')) {
@@ -2338,16 +2369,7 @@ $('#tab_compilation_illustration').on('show.bs.tab', function () {
     let v = projectObj.project.property.compilationIllustration ? projectObj.project.property.compilationIllustration : '';
     $('#compilationIllustration textarea').val(v);
 });
-$('#property_ok').click(async function () {
-    //test-----
-    /*$.bootstrapLoading.start();
-    let xmlObj = new XMLStandard(userID, 1);
-    await xmlObj.toXml(projectObj.project.ID());
-    console.log(xmlObj);
-    xmlObj = null;
-    $.bootstrapLoading.end();
-    return;*/
-    //test-----
+$('#property_ok').click(function () {
     let project = projectObj.project,
         projectID = project.ID(),
         properties = {},
@@ -3153,6 +3175,9 @@ function disableTools(){
     $('.bottom-tools').remove();
     //导入
     $('#importConfirm').addClass('disabled');
+    //导出
+    $('#export-confirm').addClass('disabled');
+    $('#exportSpan .dropdown-item').addClass('disabled');
     //选项
     $('#generalOpts1').prop('disabled', 'disabled');
     $('#generalOpts2').prop('disabled', 'disabled');
@@ -3291,3 +3316,9 @@ $('#calcBaseFeeRateConf').click(function () {
 $('#menu_calc_program_manage').click(function () {
     $('#tab_calc_program_manage').click();
 });
+$('#menu_index_info').click(function () {
+    $('#tab_index').click();
+});
+
+//导出接口
+ExportView.exportListener();

+ 80 - 44
web/building_saas/pm/html/project-management.html

@@ -239,6 +239,17 @@
                         </div>
                     </div>
                     <div class="form-group row">
+                        <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计价规则</label>
+                        <div class="col">
+                            <select class="form-control  form-control-sm" id="proj-valuation">
+                                <% for (let valuation of valuationOpts) { %>
+                                <option value="<%= valuation.id %>"><%= valuation.name %></option>
+                                <% } %>
+                            </select>
+                        </div>
+                    </div>
+                    <span class="form-text text-danger" id="proj-valuation-info" style="display: none;">请选择计价规则</span>
+                    <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">文件类型</label>
                         <div class="col">
                             <div class="custom-control custom-radio custom-control-inline">
@@ -336,6 +347,17 @@
                     <span class="form-text text-info" id="poj-name-info" style="display: none;">新建 “汽车生产车间5”</span>
                     <div id="newProjectSet" style="display: none">
                         <div class="form-group row">
+                            <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计价规则</label>
+                            <div class="col">
+                                <select class="form-control  form-control-sm" id="valuation">
+                                    <% for (let valuation of valuationOpts) { %>
+                                    <option value="<%= valuation.id %>"><%= valuation.name %></option>
+                                    <% } %>
+                                </select>
+                            </div>
+                        </div>
+                        <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>
+                        <div class="form-group row">
                             <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">文件类型</label>
                             <div class="col">
                                 <div class="custom-control custom-radio custom-control-inline">
@@ -403,27 +425,27 @@
                     </div>
                 </form>
                 <form id="secondStep" style="display: none">
-                    <div class="form-group row">
+                    <!--<div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计价方式</label>
                         <div class="col">
                             <div class="custom-control custom-radio custom-control-inline">
                                 <input type="radio" value="bill" checked id="radioBill" name="valuation_type" class="custom-control-input">
                                 <label class="custom-control-label" for="radioBill">清单计价</label>
                             </div>
-                           <!-- <div class="custom-control custom-radio custom-control-inline">
+                           &lt;!&ndash; <div class="custom-control custom-radio custom-control-inline">
                                 <input type="radio" value="ration" id="radioRation" name="valuation_type" class="custom-control-input">
                                 <label class="custom-control-label" for="radioRation">定额计价</label>
-                            </div>-->
+                            </div>&ndash;&gt;
                         </div>
-                    </div>
-                    <div class="form-group row">
+                    </div>-->
+                    <!--<div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计价规则</label>
                         <div class="col">
                             <select class="form-control  form-control-sm" id="valuation">
                             </select>
                         </div>
                     </div>
-                    <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>
+                    <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>-->
                     <div class="form-group row" id="regionDiv" style="display: none;">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">地&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;区</label>
                         <div class="col">
@@ -734,10 +756,10 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">欢迎使用纵横建筑计价</h5>
+                <h5 id="progress-title" class="modal-title">欢迎使用纵横建筑计价</h5>
             </div>
             <div class="modal-body">
-                <h5 class="my-3">首次加载例题,请稍候……</h5>
+                <h5 id="progress-content" class="my-3">首次加载例题,请稍候……</h5>
                 <div class="progress mb-3">
                     <div class="progress-bar progress-bar-striped progress-bar-animated" id="progressBar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
                 </div>
@@ -764,7 +786,7 @@
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">选择文件</label>
                         <div class="col">
                             <div class="custom-file custom-file-sm">
-                                <input type="file" class="custom-file-input" id="customFile" accept=".xml,.qtf,.QTF,.xlsx" lang="zh">
+                                <input type="file" class="custom-file-input" id="customFile" accept=".xml,.qtf,.QTF" lang="zh">
                                 <label class="custom-file-label" for="customFile" style="white-space: nowrap; overflow: hidden;">请选择导入文件</label>
                             </div>
                             <div class="alert alert-success mt-3" id="uploadAlert" role="alert" style="display: none;"></div>
@@ -779,13 +801,34 @@
                         </div>
                     </div>
                     <div class="form-group row">
+                        <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">文件类型</label>
+                        <div class="col">
+                            <div class="custom-control custom-radio custom-control-inline">
+                                <input type="radio" value="1" checked id="radioTender-import" name="fileKind-import" class="custom-control-input">
+                                <label class="custom-control-label" for="radioTender-import">投标</label>
+                            </div>
+                            <div class="custom-control custom-radio custom-control-inline">
+                                <input type="radio" value="2" disabled id="radioBid-import" name="fileKind-import" class="custom-control-input">
+                                <label class="custom-control-label" for="radioBid-import">招标</label>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计价规则</label>
                         <div class="col">
-                            <select class="form-control form-control-sm">
-                                <option selected>赣建价[2017]7号</option>
-                                <option value="1">One</option>
-                                <option value="2">Two</option>
-                                <option value="3">Three</option>
+                            <select id="import-valuation" class="form-control form-control-sm">
+                                <% for (let valuation of valuationOpts) { %>
+                                <option value="<%= valuation.id %>"><%= valuation.name %></option>
+                                <% } %>
+                            </select>
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计税方法</label>
+                        <div class="col">
+                            <select id="import-taxType" class="form-control form-control-sm">
+                                <option value="1">一般计税法</option>
+                                <option value="2">简易计税法</option>
                             </select>
                         </div>
                     </div>
@@ -807,52 +850,45 @@
             </div>
             <div class="modal-body">
                 <form>
-                    <p>该文件共有10个单位工程待导入</p>
+                    <p>该文件共有0个单位工程待导入</p>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">单项工程</label>
                         <div class="col">
-                            <input id="tbc-engName" type="text" class="form-control form-control-sm" value="AA单项工程" readonly="">
+                            <input id="tbc-engName" type="text" class="form-control form-control-sm" value="" readonly="">
                         </div>
                     </div>
+                    <span class="form-text text-danger" id="tbc-engName-info" style="display: none;">无有效单项工程</span>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">单位工程</label>
                         <div class="col">
-                            <input id="tbc-tenderName" type="text" class="form-control form-control-sm" value="XXXX单位" readonly="">
+                            <input id="tbc-tenderName" type="text" class="form-control form-control-sm" value="" readonly="">
                         </div>
                     </div>
+                    <span class="form-text text-danger" id="tbc-tenderName-info" style="display: none;">无有效单位工程</span>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">工程专业</label>
                         <div class="col">
-                            <select id="tbc-engineering" class="form-control form-control-sm" readonly>
-                                <option selected>建筑工程</option>
-                                <option value="1">One</option>
-                                <option value="2">Two</option>
-                                <option value="3">Three</option>
+                            <select id="tbc-engineering" class="form-control form-control-sm">
                             </select>
                         </div>
                     </div>
+                    <span class="form-text text-danger" id="tbc-engineering-info" style="display: none;">无有效工程专业</span>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">费用标准</label>
                         <div class="col">
-                            <select class="form-control form-control-sm">
-                                <option selected>建筑工程</option>
-                                <option value="1">One</option>
-                                <option value="2">Two</option>
-                                <option value="3">Three</option>
+                            <select id="tbc-feeStandard" class="form-control form-control-sm">
                             </select>
                         </div>
                     </div>
+                    <span class="form-text text-danger" id="tbc-feeStandard-info" style="display: none;">无有效费用标准</span>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">计算程序</label>
                         <div class="col">
-                            <select class="form-control form-control-sm">
-                                <option selected>标准模板</option>
-                                <option value="1">One</option>
-                                <option value="2">Two</option>
-                                <option value="3">Three</option>
+                            <select id="tbc-calcProgram" class="form-control form-control-sm">
                             </select>
                         </div>
                     </div>
+                    <span class="form-text text-danger" id="tbc-calcProgram-info" style="display: none;">无有效计算程序</span>
                     <div class="d-flex justify-content-center">
                         <div class="btn-group btn-group-sm " role="group">
                             <button id="tbc-prev" type="button" class="btn btn-outline-primary" disabled="">上一工程</button>
@@ -864,7 +900,7 @@
             </div>
             <div class="modal-footer">
                 <a id="import-prev" href="javascript:void(0);" data-toggle="modal" data-target="#import1" class="btn btn-primary">上一步</a>
-                <button type="button" class="btn btn-primary">确认导入</button>
+                <button disabled id="import-confirm" type="button" class="btn btn-primary">确认导入</button>
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
             </div>
         </div>
@@ -873,11 +909,18 @@
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script>GC.Spread.Sheets.LicenseKey = '<%- LicenseKey %>';</script>
-<!--<script src="/lib/x2js/xml2json.min.js"></script>-->
+<script src="/lib/x2js/xml2json.min.js"></script>
+<script type="text/javascript">
+    let billValuation = JSON.parse('<%- billValuation %>');
+    let rationValuation = JSON.parse('<%- rationValuation %>');
+    let engineeringList = '<%- engineeringList %>';
+    let compilationData = '<%- compilationData %>';
+    compilationData = JSON.parse(compilationData.replace(/[\s\r\n]/g, ""));//去掉空格字符
+    console.log(billValuation);
+</script>
 <!-- inject:js -->
 <script src="/web/building_saas/js/global.js"></script>
 <script src="/public/web/uuid.js"></script>
-<script src="/public/web/PerfectLoad.js"></script>
 <script src="/public/web/date_util.js"></script>
 <script src="/web/building_saas/pm/js/pm_tree.js"></script>
 <script src="/public/web/id_tree.js"></script>
@@ -888,10 +931,10 @@
 <script src="/lib/JSExpressionEval_src/Date.js"></script>
 <script src="/web/building_saas/glj/js/socket.io.slim.js"></script>
 <script src="/public/web/socket/connection.js"></script>
+<script src="/web/building_saas/main/js/models/importStandardInterface.js"></script>
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_newMain.js"></script>
-<!--<script src="/web/building_saas/main/js/models/importStandardInterface.js"></script>
-<script src="/web/building_saas/pm/js/pm_import.js"></script>-->
+<script src="/web/building_saas/pm/js/pm_import.js"></script>
 <script src="/web/building_saas/pm/js/pm_gc.js"></script>
 <script src="/web/building_saas/pm/js/pm_share.js"></script>
 <!-- zTree -->
@@ -907,11 +950,4 @@
 <script type="text/javascript">
     autoFlashHeight();
 </script>
-<script type="text/javascript">
-    let billValuation = '<%- billValuation %>';
-    let rationValuation = '<%- rationValuation %>';
-    let engineeringList = '<%- engineeringList %>';
-    let compilationData = '<%- compilationData %>';
-    compilationData = JSON.parse(compilationData.replace(/[\s\r\n]/g, ""));//去掉空格字符
-</script>
 </html>

+ 7 - 1
web/building_saas/pm/js/pm_ajax.js

@@ -24,7 +24,7 @@ var GetAllProjectData = function (callback) {
     });
 }
 // 更新数据到服务器
-var UpdateProjectData = function (updateData, callback) {
+var UpdateProjectData = function (updateData, callback, errCB) {
     $.ajax({
         type:"POST",
         url: '/pm/api/updateProjects',
@@ -36,10 +36,16 @@ var UpdateProjectData = function (updateData, callback) {
             if (result.error === 0) {
                 callback(result.data);
             } else {
+                if (errCB) {
+                    errCB();
+                }
                 alert('error: ' + result.message);
             }
         },
         error: function(jqXHR, textStatus, errorThrown){
+            if (errCB) {
+                errCB();
+            }
             alert('error ' + textStatus + " " + errorThrown);
         }
     });

+ 365 - 20
web/building_saas/pm/js/pm_import.js

@@ -7,11 +7,12 @@
  * @date 2019/5/15
  * @version
  */
-
+//操作接口为eventListen
 const importView = (() => {
+    let importXML = null;
     let xmlObj = null;  //导入xml转化后的对象
     let tbcObj = null;  //待确认对象
-    //显示、隐藏提示相关信息
+    //显示、隐藏提示上传文件窗口相关提示信息
     function showUploadAlert(success, msg){
         if(!success){
             $('#uploadAlert').removeClass('alert-success');
@@ -35,42 +36,107 @@ const importView = (() => {
         for (let eng of xmlObj.engs) {
             if (Array.isArray(eng.tenders)) {
                 for (let tender of eng.tenders) {
+                    tender.temp = {};  //暂时存放的信息(不是从导入文件中获取的,记录当前工程已阅、选择的费用标准、计算程序)
                     tender.engName = eng.name;
                 }
-                rst = [...rst, ...eng.tenders];
+                rst.push(...eng.tenders);
             }
         }
         return rst;
     }
+    //确认界面提示信息隐藏
+    function hideTBCInfo() {
+        $('#tbc-engName-info').hide();
+        $('#tbc-tenderName-info').hide();
+        $('#tbc-engineering-info').hide();
+        $('#tbc-calcProgram-info').hide();
+    }
     //待确认界面相关
     class TBC {
-        constructor(xmlObj) {
+        constructor(xmlObj, fileKind, valuation, taxType) {
             this.datas = getTenderDatas(xmlObj);
-            this.curIdx = 0;
+            this.fileKind = fileKind;   //文件类型
+            this.valuationType = 'bill';    //计价方式 暂时默认为清单计价
+            this.valuation = valuation;     //计价规则数据
+            this.taxType = taxType; //计税方法
+            this.engineeringList = valuation ? valuation.engineering_list : []; //工程专业库数据
+            this.curIdx = 0;    //当前单位工程数据索引
             this.init();
         }
         //初始化
         init() {
-            this.next(0);   //初始化的时候,显示第第一份数据
+            this.next(this.curIdx);
             $('#importInterface .modal-content:eq(1) p:eq(0)').text(`该文件共有${this.datas.length}个单位工程待导入`);  //信息统计信息
         }
+        checkConfirmed() {
+            //检查数据是否都确认过了
+            let allConfirmed = this.datas.every(data => data.temp.confirmed);
+            if (allConfirmed) {
+                $('#import-confirm').prop('disabled', false);
+            }
+        }
+        //检测当前待确认工程是否有效,有效才可确认
+        checkValid() {
+            let engName = $('#tbc-engName').val();
+            if (!engName) {
+                return $('#tbc-engName-info').show();
+            } else {
+                $('#tbc-engName-info').hide();
+            }
+            let tenderName = $('#tbc-tenderName').val();
+            if (!tenderName) {
+                return $('#tbc-tenderName-info').show();
+            } else {
+                $('#tbc-tenderName-info').hide();
+            }
+            let engineering = $('#tbc-engineering').val();
+            if (!engineering) {
+                return $('#tbc-engineering-info').show();
+            } else {
+                $('#tbc-engineering-info').hide();
+            }
+            let feeStandard = $('#tbc-feeStandard').val();
+            if (!feeStandard) {
+                return $('#tbc-feeStandard-info').show();
+            } else {
+                $('#tbc-feeStandard-info').hide();
+            }
+            let calcProgram = $('#tbc-calcProgram').val();
+            if (!calcProgram) {
+                return $('#tbc-calcProgram-info').show();
+            } else {
+                $('#tbc-calcProgram-info').hide();
+            }
+            return null;
+        }
         //下一工程
         next(idx = null) {
             this.curIdx = idx !== null ? idx : this.curIdx + 1;
+            if (this.curIdx && this.checkValid()) {
+                this.curIdx--;
+                return;
+            }
             let curData = this.datas[this.curIdx];
             //显示这个工程的相关信息
             $('#tbc-engName').val(curData.engName || '');
             $('#tbc-tenderName').val(curData.name || '');
             $('#tbc-engineering').val(curData.engineering || '');
-            curData.confirmed = true;   //增加确认信息(已读)
+            curData.temp.confirmed = true;   //增加确认信息(已读)
             if (this.curIdx === this.datas.length -1) { //到最后一个数据了,无法点击下一工程
                 $('#tbc-next').prop('disabled', true);
+            } else {
+                $('#tbc-next').prop('disabled', false);
             }
             if (this.curIdx !== 0) {    //不为第一个数据,可以点击上一工程
                 $('#tbc-prev').prop('disabled', false);
+            } else {
+                $('#tbc-prev').prop('disabled', true);
             }
             //更新x/x信息
             $('#tbc-info').text(`${this.curIdx + 1}/${this.datas.length} 已确认`);
+            //更新选项信息
+            this.initFeeOpts(curData);
+            this.checkConfirmed();
         }
         //上一工程
         prev(idx = null) {
@@ -81,38 +147,156 @@ const importView = (() => {
             $('#tbc-engineering').val(curData.engineering || '');
             if (this.curIdx === 0) {    //到第一个数据了,无法点击上一工程
                 $('#tbc-prev').prop('disabled', true);
+            } else {
+                $('#tbc-prev').prop('disabled', false);
             }
             if (this.curIdx !== this.datas.length -1 ) {    //不为最后一个数据了,可以点击下一工程
                 $('#tbc-next').prop('disabled', false);
+            } else {
+                $('#tbc-next').prop('disabled', true);
             }
             //更新x/x信息
             $('#tbc-info').text(`${this.curIdx + 1}/${this.datas.length} 已确认`);
+            //更新选项信息
+            this.initFeeOpts(curData);
+            this.checkConfirmed();
         }
+        /*
+         *  初始化工程的费用选项等相关信息(专业工程、费用标准、计算程序等)
+         *  根据导入文件提取的专业工程等数据确定,需要我们软件有对应的工程专业数据,否则下拉选择为空
+         *  @param {Object}tenderData(当前确认单位工程数据) {Array}engineeringList(当前计价规则下的工程专业数据)
+         *  @return {void}
+         * */
+        initFeeOpts(tenderData) {
+            $('#tbc-engineering').empty();  //清空工程专业选项
+            $('#tbc-feeStandard').empty();  //清空费用标准选项
+            $('#tbc-calcProgram').empty();  //清空计算程序选项
+            let engineerings = [];
+            if (tenderData.temp.engineering) {
+                engineerings = this.engineeringList.filter(data => data.lib.name === tenderData.temp.engineering);
+            } else {
+                engineerings = this.engineeringList.filter(data => data.lib.name === tenderData.engineering);
+                tenderData.temp.engineering = tenderData.engineering;
+            }
+            //文件里的工程专业跟软件里的对应不上,取第一个
+            if (!engineerings.length) {
+                let firstEngineering = this.engineeringList[0];
+                engineerings = this.engineeringList.filter(data => data.lib.name === firstEngineering.lib.name);
+                tenderData.temp.engineering = engineerings[0] ? engineerings[0].lib.name : tenderData.engineering;
+            }
+            if (!engineerings.length) {
+                return;
+            }
+            //工程专业名称去重
+            let engineeringNames = [...new Set(this.engineeringList.map(data => data.lib.name))];
+            let engineeringHtml = engineeringNames.map(name =>
+             `<option ${tenderData.temp.engineering === name ? 'selected' : ''} value="${name}">${name}</option>`);
+             $('#tbc-engineering').html(engineeringHtml);
+            //$('#tbc-engineering').html(`<option selected value="${tenderData.engineering}">${tenderData.engineering}</option>`);
+            //费用标准,若当前工程有费用标准数据(该数据本身没有费用标准数据,选择过了,就会记录),则选中该费用标准
+            let feeOptsHtml = engineerings.map(data =>
+                `<option ${tenderData.temp.feeStandard === data.lib.feeName ? 'selected' : ''} value="${data.lib.feeName}">${data.lib.feeName}</option>`).join('');
+            $('#tbc-feeStandard').html(feeOptsHtml);
+            //记录选中的费用标准
+            tenderData.temp.feeStandard = $('#tbc-feeStandard').val();
+            //根据工程专业及费用标准确定的当前选中的工程专业库
+            let curEngineering = engineerings.find(data => data.lib.feeName === tenderData.temp.feeStandard) || engineerings[0];
+            //根据计税方法过滤出来的计税组合
+            let taxDatas = curEngineering.lib.tax_group.filter(data => data.taxType == this.taxType);
+            //计算程序,若当前工程有计算程序(该数据本身没有计算程序数据,选择过了,就会记录),则选中该计算程序
+            let calcOptsHtml = taxDatas.map(data =>
+                `<option ${tenderData.temp.calcProgram === data.program_lib.name ? 'selected' : ''} value="${data.program_lib.name}">${data.program_lib.name}</option>`);
+            $('#tbc-calcProgram').html(calcOptsHtml);
+            tenderData.temp.calcProgram = $('#tbc-calcProgram').val();
+        }
+    }
+    /*
+     * 根据条件获取计税组合数据
+     * @param {Object}query ({engineeringName, feeName, taxType, calcProgram}) {Array}engineeringList(当前计价规则下的所有工程专业数据)
+     * @return {Object}
+     * */
+    function getTaxData(query, engineeringList) {
+        //工程专业名称 + 费用标准名称 确定一个工程专业数据
+        let engineering = engineeringList.find(data => query.engineeringName === data.lib.name &&
+                                                       query.feeStandard === data.lib.feeName);
+        if (!engineering || !Array.isArray(engineering.lib.tax_group)) {
+            return null;
+        }
+        return engineering.lib.tax_group.find(data => query.taxType == data.taxType &&
+                                                          query.calcProgram === data.program_lib.name);
+    }
+    //获取单位工程项目属性的一些数据(新建单位工程需要,前端能获取到的一些数据,还有一些数据需要后端获取: rootProjectID, projectFeature..)
+    /*
+    * @param {Object}tbcObj(TBC实例) {Object}curData(单位工程数据)
+    * @return {Object}
+    * */
+    function getProperty(tbcObj, curData) {
+        if (!tbcObj) {
+            throw '存在无效数据,无法生成项目。';
+        }
+        //计税数据
+        let query = {
+            engineeringName: curData.temp.engineering || curData.engineering,
+            feeStandard: curData.temp.feeStandard,
+            taxType: tbcObj.taxType,    //取导入时选择的计税方法,不读取文件中的计税方法
+            calcProgram: curData.temp.calcProgram
+        };
+        let taxData = getTaxData(query, tbcObj.engineeringList);
+        if (!taxData) {
+            throw '无效计税数据,无法生成项目。';
+        }
+        //当前工程专业数据
+        let curEngineering = tbcObj.engineeringList.find(data => query.engineeringName === data.lib.name &&
+        query.feeStandard === data.lib.feeName);
+        return {
+            region: '全省',   //地区
+            valuationType: tbcObj.valuationType,    //计价方式
+            valuation: tbcObj.valuation.id, //计价规则
+            valuationName: tbcObj.valuation.name,
+            engineering_id: curEngineering.engineering_id,  //工程专业
+            engineeringName: curEngineering.lib.name,
+            taxType: parseInt(tbcObj.taxType),    //计税方法
+            isInstall: !!curEngineering.lib.isInstall,  //是安装工程?
+            feeStandardName: curEngineering.lib.feeName,    //费用标准
+            engineering: curEngineering.lib.engineering,    //定额取费专业
+            projectEngineering: curEngineering.lib.projectEngineering,  //单位工程取费专业
+            featureLibID: curEngineering.lib.feature_lib[0] ? curEngineering.lib.feature_lib[0].id : '',    //工程特征
+            calcProgram: {name: taxData.program_lib.name, id: taxData.program_lib.id},  //计算程序
+            colLibID: taxData.col_lib.id,   //列设置
+            templateLibID: taxData.template_lib.id, //清单模板
+            unitPriceFile: {name: curData.name, id: ''},    //新建单价文件
+            feeFile: {name: curData.name, id: `newFeeRate@@${taxData.fee_lib.id}`}  //新建费率文件
+        };
     }
     function eventListen() {
         //选择文件
         $('#customFile').change(async function() {
             let file = $(this)[0].files[0];
+            $('#import-confirm').prop('disabled', true);    //确认导入无效
+            $('.custom-file-label').text(`${file ? file.name : ''}`);   //设置选择框文本
+            $('#uploadAlert').hide();
+            $('.selFile').hide();
+            hideTBCInfo();
             if (file) {
-                let reg = /(xml|XML|qtf|QTF)$/g;
+                let reg = /(xml|XML|qtf|QTF)$/;
                 if(file.name && !reg.test(file.name)){
                     $('.selFile').hide();
                     showUploadAlert(false, '请选择xml或qtf文件。');
-                    $(this).val('');
                     return;
                 }
-                $('.custom-file-label').text(`${file.name}`);   //设置选择框文本
-                $('#uploadAlert').hide();
                 $.bootstrapLoading.start();
                 $('#loadingPage').css('z-index', '2000');
                 //转换数据
-                let importXML = new ImportXML();
+                importXML = new ImportXML();
                 try {
                     xmlObj = await importXML.extractData(file);
-                    $('.selFile input').val(xmlObj && xmlObj.name ? xmlObj.name : '');
+                    $('.selFile input:eq(0)').val(xmlObj && xmlObj.name ? xmlObj.name : '');
+                    $('.selFile input[name="fileKind-import"]:eq(0)').prop('checked', true);    //文件类型恢复成投标
+                    $('#import-taxType').val('1');  //计税方法显示回默认的一般计税法
                     $('.selFile').show();   //显示建设项目、计价规则
                 } catch (err) {
-                    showUploadAlert(false, '请选择xml或qtf文件。');
+                    console.log(err);
+                    showUploadAlert(false, err);
                     $(this).val('');
                 }
                 $.bootstrapLoading.end();
@@ -125,32 +309,176 @@ const importView = (() => {
                 showUploadAlert(false, '请选择导入文件。');
                 return;
             }
-            let projectName = $('.selFile input').val();
+            if (!xmlObj) {
+                showUploadAlert(false, '不存在有效数据。');
+                return;
+            }
+            let projectName = $('.selFile input:eq(0)').val();
             if (!projectName) {
                 showUploadAlert(false, '不存在有效建设项目。');
                 return;
             }
+            //文件类型
+            let fileKind = $('.selFile input[name="fileKind-import"]:checked').val();
+            if (!fileKind) {
+                showUploadAlert(false, '不存在有效文件类型。');
+            }
+            //计价规则
+            let valuation = $('#import-valuation').val();
+            if (!valuation) {
+                showUploadAlert(false, '不存在有效计价规则。');
+                return;
+            }
+            //计税方法
+            let taxType = $('#import-taxType').val();
+            if (!taxType) {
+                showUploadAlert(false, '不存在有效计税方法。');
+                return;
+            }
+            if (!xmlObj.engs.length) {
+                showUploadAlert(false, '不存在单项工程数据。');
+                return;
+            }
+            if (!getTenderDatas(xmlObj).length) {
+                showUploadAlert(false, '不存在单位工程数据。');
+                return;
+            }
             $('#importInterface .modal-content:eq(0)').hide();  //隐藏第一步内容
             $('#importInterface .modal-content:eq(1)').show();  //显示第二步内容
-            console.log(getTenderDatas(xmlObj));
-            console.log(xmlObj);
-            tbcObj = new TBC(xmlObj);
+            //console.log(getTenderDatas(xmlObj));
+            //console.log(xmlObj);
+            let selValuation = billValuation.find(data => data.id === valuation);
+            tbcObj = new TBC(xmlObj, fileKind, selValuation, taxType);
         });
         //上一步
         $('#import-prev').click(function () {
             $('#importInterface .modal-content:eq(0)').show();  //显示第一步内容
             $('#importInterface .modal-content:eq(1)').hide();  //隐藏第二步内容
+            hideTBCInfo();
+            $('#import-confirm').prop('disabled', true);    //确认导入无效
+            //清空确认字段
+            if (tbcObj) {
+                for (let data of tbcObj.datas) {
+                    delete data.temp.confirmed;
+                }
+            }
+        });
+        //变换专业工程
+        $('#tbc-engineering').change(function () {
+            let curData = tbcObj ? tbcObj.datas[tbcObj.curIdx] : null;
+            if (!curData) {
+                return;
+            }
+            curData.temp.engineering = $(this).val();
+            tbcObj.initFeeOpts(curData);
+        });
+        //变换费用标准
+        $('#tbc-feeStandard').change(function () {
+            let curData = tbcObj ? tbcObj.datas[tbcObj.curIdx] : null;
+            if (!curData) {
+                return;
+            }
+            curData.temp.feeStandard = $(this).val();
+            tbcObj.initFeeOpts(curData);
+        });
+        //变换计算程序
+        $('#tbc-calcProgram').change(function () {
+            let curData = tbcObj ? tbcObj.datas[tbcObj.curIdx] : null;
+            if (!curData) {
+                return;
+            }
+            curData.temp.calcProgram = $(this).val();
+            tbcObj.initFeeOpts(curData);
         });
         //待确认-下一工程
         $('#tbc-next').click(function () {
             tbcObj.next();
+
         });
         //待确认-上一工程
         $('#tbc-prev').click(function () {
             tbcObj.prev();
+            hideTBCInfo();
+        });
+        //确认导入
+        $('#import-confirm').click(async function () {
+            if (STATE.importing) {
+                return;
+            }
+            STATE.importing = true;
+            if (tbcObj && tbcObj.checkValid()) {
+                return;
+            }
+            let pr = new SCComponent.InitProgressBar($('#progress'), $('#progress-title'), $('#progress-content'), $('#progressBar'));
+            try {
+                //建设项目设置选择的文件类型和选择的计税方法
+                xmlObj.property.fileKind = tbcObj.fileKind;
+                xmlObj.property.taxType = tbcObj.taxType;
+                //确定使用的计税组合
+                tbcObj.datas.map(data => {
+                    data.property = getProperty(tbcObj, data);
+                    //默认定额库
+                    let curEngineering = tbcObj.engineeringList.find(enData => data.temp.engineering === enData.lib.name &&
+                    data.temp.feeStandard === enData.lib.feeName);
+                    let defaultLib = curEngineering.lib.ration_lib.find(data => data.isDefault) || curEngineering.lib.ration_lib[0];
+                    data.defaultRationLib = parseInt(defaultLib.id);
+                    //此费用定额下可用的定额库id,人材机库id
+                    data.rationLibIDs = curEngineering.lib.ration_lib.map(data => parseInt(data.id));
+                    data.gljLibIDs = curEngineering.lib.glj_lib.map(data => parseInt(data.id));
+                });
+                //确定生成建设项目的父、前、后节点ID
+                let {parentProjectID, preProjectID, nextProjectID} = projTreeObj.getRelProjectID(projTreeObj.tree.selected);
+                xmlObj.ParentID = parentProjectID;
+                xmlObj.preID = preProjectID;
+                xmlObj.NextSiblingID = nextProjectID;
+                //确定建设项目的名称(不允许重复)
+                let sameDepthProjs = getProjs(projTreeObj.tree.selected);
+                if (sameDepthProjs.find(node => node.data.name === xmlObj.name)) {
+                    xmlObj.name += `(${moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')})`;
+                }
+                //console.log(xmlObj);
+                $('#importInterface').modal('hide');
+                /*let importData = await importXML.transformData(xmlObj);
+                console.log(importData);*/
+                pr.start('导入文件', '正在生成文件,请稍候……');
+                let importData = await importXML.transformData(xmlObj);
+                let blob = new Blob([JSON.stringify(importData)], {type: 'text/plain;charset=utf-8'});
+                console.log(blob);
+                let formData = new FormData();
+                formData.append('file', blob);
+                $.ajax({
+                    url: '/pm/import/importInterface',
+                    type: 'POST',
+                    data: formData,
+                    cache: false,
+                    contentType: false,
+                    processData: false,
+                    timeout: 1000 * 60 * 3, //3分钟
+                    success: function(response){
+                        if (response.data && Array.isArray(response.data)) {
+                            doAfterImport(response.data);
+                        }
+                        pr.end();
+                        setTimeout(function () {
+                            STATE.importing = false;
+                        }, 500);
+                    },
+                    error: function(jqXHR){
+                        pr.end();
+                        throw `与服务器通信发生错误${jqXHR.status} ${jqXHR.statusText}`;
+                    }
+                });
+            } catch (err) {
+                setTimeout(function () {
+                    STATE.importing = false;
+                }, 500);
+                pr.end();
+                alert(err);
+            }
         });
         //导入窗口消失后
         $('#importInterface').on('hidden.bs.modal', function () {
+            importXML = null;
             xmlObj = null;  //重置数据
             tbcObj = null;
             $('#importInterface .modal-content:eq(0)').show();  //显示第一步内容
@@ -159,8 +487,25 @@ const importView = (() => {
             $('.custom-file-label').text('');   //设置选择框文本
             $('#uploadAlert').hide();   //隐藏提示
             $('.selFile').hide();   //隐藏建设项目及计价规则
+            $('#import-confirm').prop('disabled', true);    //确认导入无效
+            $('.selFile input[name="fileKind-import"]:eq(0)').prop('checked', true);    //文件类型恢复成投标
+            $('#import-taxType').val('1');  //显示回一般计税
+            hideTBCInfo();
         });
     }
+    //projectDatas在后端已经按照顺序排过了: project eng1 tender1-1 tender1-2 eng2 tender2-1 tender2-2
+    function doAfterImport(projectDatas) {
+        //插入节点
+        let lastNode;
+        for (let data of projectDatas) {
+            data.feeStandardName = data.property && data.property.feeStandardName || ''; //工程专业列显示用
+            let parent = projTreeObj.tree.items.find(node => node.data.ID === data.ParentID),
+                next = projTreeObj.tree.items.find(node => node.data.ID === data.NextSiblingID);
+            lastNode = projTreeObj.insert(data, parent, next);
+        }
+        if(lastNode) {
+            projTreeObj.workBook.getSheet(0).showRow(lastNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+        }
+    }
     return {eventListen};
-})();
-
+})();

File diff suppressed because it is too large
+ 345 - 142
web/building_saas/pm/js/pm_newMain.js


+ 1 - 1
web/over_write/js/chongqing_2018.js

@@ -287,7 +287,7 @@ if(typeof baseFigureMap !== 'undefined'){
         '甲供定额施工机具使用费': {base: 'JGDEJJJXF', class: 'RCJ'},
         '甲供人工费': {base: 'JGRGF', class: 'RCJ'},
         '甲供材料费': {base: 'JGCLF', class: 'RCJ'},
-        '甲供施工机具使用费': {base: 'JGJXF', class: 'RCJ'},
+        '甲供施工机具使用费': {base: 'JGJXF', class: 'RCJ'},
         '甲供主材费': {base: 'JGZCF', class: 'RCJ'},
         '甲定定额人工费': {base: 'JDDEJJRGF', class: 'RCJ'},
         '甲定定额材料费': {base: 'JDDEJJCLF', class: 'RCJ'},