Bladeren bron

Merge branch 'master' of http://192.168.1.12:3000/SmartCost/ConstructionCost

TonyKang 7 jaren geleden
bovenliggende
commit
6beb7d7b79
82 gewijzigde bestanden met toevoegingen van 2838 en 997 verwijderingen
  1. 2 1
      config/config.js
  2. 8 2
      config/gulpConfig.js
  3. 3 3
      modules/bills_lib/models/bills_lib_schemas.js
  4. 67 4
      modules/complementary_glj_lib/models/gljModel.js
  5. 1 0
      modules/complementary_ration_lib/models/searchModel.js
  6. 2 1
      modules/glj/controllers/glj_controller.js
  7. 8 10
      modules/glj/models/unit_price_file_model.js
  8. 10 6
      modules/glj/models/unit_price_model.js
  9. 33 0
      modules/main/controllers/bills_controller.js
  10. 34 0
      modules/main/controllers/project_controller.js
  11. 1 0
      modules/main/controllers/quantity_detail_controller.js
  12. 47 0
      modules/main/facade/bill_facade.js
  13. 1 0
      modules/main/facade/calc_program_facade.js
  14. 50 0
      modules/main/facade/project_facade.js
  15. 4 4
      modules/main/facade/quantity_detail_facade.js
  16. 3 1
      modules/main/models/bills.js
  17. 2 1
      modules/main/models/ration.js
  18. 2 1
      modules/main/routes/bills_route.js
  19. 3 0
      modules/main/routes/project_route.js
  20. 59 2
      modules/options/controllers/optionsController.js
  21. 57 4
      modules/options/models/optionTypes.js
  22. 29 1
      modules/options/models/optionsModel.js
  23. 10 1
      modules/options/models/schemas.js
  24. 5 1
      modules/pm/models/project_model.js
  25. 2 1
      modules/pm/models/project_schema.js
  26. 2 2
      modules/pm/models/templates/bills_template_model.js
  27. 2 1
      modules/pm/models/templates/schemas/bills_template.js
  28. 2 1
      modules/ration_glj/facade/glj_calculate_facade.js
  29. 20 5
      modules/ration_glj/facade/ration_glj_facade.js
  30. 2 1
      modules/ration_glj/models/ration_glj_temp.js
  31. 8 0
      public/web/common_util.js
  32. 14 10
      public/web/id_tree.js
  33. 38 6
      public/web/socket/connection.js
  34. 1 1
      public/web/tree_sheet/tree_sheet_controller.js
  35. 34 25
      public/web/tree_sheet/tree_sheet_helper.js
  36. 12 7
      socket.js
  37. 15 11
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  38. 29 4
      web/building_saas/complementary_glj_lib/js/glj.js
  39. 180 0
      web/building_saas/complementary_glj_lib/js/gljClassTree.js
  40. 1 1
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  41. 1 1
      web/building_saas/complementary_ration_lib/html/dinge.html
  42. 5 1
      web/building_saas/complementary_ration_lib/js/ration_coe.js
  43. 3 0
      web/building_saas/css/main.css
  44. 4 2
      web/building_saas/glj/js/common_spread.js
  45. 81 33
      web/building_saas/glj/js/composition.js
  46. 1 0
      web/building_saas/glj/js/composition_spread.js
  47. 65 13
      web/building_saas/glj/js/project_glj.js
  48. 74 4
      web/building_saas/main/html/main.html
  49. 12 12
      web/building_saas/main/js/calc/bills_calc.js
  50. 9 11
      web/building_saas/main/js/calc/ration_calc.js
  51. 1 1
      web/building_saas/main/js/controllers/project_controller.js
  52. 87 25
      web/building_saas/main/js/models/bills.js
  53. 10 3
      web/building_saas/main/js/models/cache_tree.js
  54. 1 6
      web/building_saas/main/js/models/calc_base.js
  55. 598 471
      web/building_saas/main/js/models/calc_program.js
  56. 24 5
      web/building_saas/main/js/models/fee_rate.js
  57. 53 8
      web/building_saas/main/js/models/main_consts.js
  58. 21 5
      web/building_saas/main/js/models/project.js
  59. 58 5
      web/building_saas/main/js/models/project_glj.js
  60. 24 9
      web/building_saas/main/js/models/quantity_detail.js
  61. 14 7
      web/building_saas/main/js/models/ration.js
  62. 1 1
      web/building_saas/main/js/models/ration_coe.js
  63. 10 10
      web/building_saas/main/js/models/ration_glj.js
  64. 6 3
      web/building_saas/main/js/views/calc_base_view.js
  65. 31 5
      web/building_saas/main/js/views/calc_program_manage.js
  66. 10 0
      web/building_saas/main/js/views/calc_program_view.js
  67. 21 0
      web/building_saas/main/js/views/character_content_view.js
  68. 6 3
      web/building_saas/main/js/views/fee_rate_view.js
  69. 44 16
      web/building_saas/main/js/views/glj_view.js
  70. 5 0
      web/building_saas/main/js/views/glj_view_contextMenu.js
  71. 42 8
      web/building_saas/main/js/views/main_tree_col.js
  72. 61 1
      web/building_saas/main/js/views/options_view.js
  73. 0 18
      web/building_saas/main/js/views/project_property_labour_coe_view.js
  74. 0 3
      web/building_saas/main/js/views/project_property_projFeature.js
  75. 357 174
      web/building_saas/main/js/views/project_view.js
  76. 1 1
      web/building_saas/main/js/views/std_bills_lib.js
  77. 8 0
      web/building_saas/main/js/views/std_ration_lib.js
  78. 1 0
      web/building_saas/main/js/views/sub_view.js
  79. 276 0
      web/building_saas/main/js/views/zlfb_view.js
  80. 1 0
      web/building_saas/pm/html/project-management.html
  81. 2 3
      web/building_saas/pm/js/pm_gc.js
  82. 6 10
      web/building_saas/pm/js/pm_main.js

+ 2 - 1
config/config.js

@@ -22,6 +22,7 @@ module.exports = {
                  "socketOptions": {
                  "connectTimeoutMS": 20000
                 }
-            }
+            }/*,
+           'useMongoClient': true*/ //报 DeprecationWarning: `open()` is deprecated in mongoose这个错时可以用这句配置
         }
 }

+ 8 - 2
config/gulpConfig.js

@@ -27,6 +27,7 @@ module.exports = {
         'public/web/date_util.js',
         'public/web/tree_table/tree_table.js',
         'public/web/common_ajax.js',
+        'lib/JSExpressionEval_src/Date.js',
         'web/building_saas/pm/js/**/*.js',
         'lib/ztree/*.js'
     ],
@@ -82,8 +83,8 @@ module.exports = {
         'public/web/id_tree.js',
         'web/building_saas/main/js/models/cache_tree.js',
         'web/building_saas/main/js/calc/calc_fees.js',
-        'web/building_saas/main/js/calc/ration_calc.js',
-        'web/building_saas/main/js/calc/bills_calc.js',
+        // 'web/building_saas/main/js/calc/ration_calc.js',
+        // 'web/building_saas/main/js/calc/bills_calc.js',
         // 'public/calc_util.js',
         'public/web/tree_sheet/tree_sheet_controller.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
@@ -107,6 +108,7 @@ module.exports = {
         'web/building_saas/main/js/views/glj_view_contextMenu.js',
         'web/building_saas/main/js/views/calc_program_view.js',
         'web/building_saas/main/js/views/confirm_modal.js',
+        'web/building_saas/main/js/views/zlfb_view.js',
         'public/web/rpt_tpl_def.js',
         'public/web/treeDataHelper.js',
         'public/web/ztree_common.js',
@@ -133,7 +135,11 @@ module.exports = {
         'public/web/common_ajax.js',
         'public/web/treeDataHelper.js',
         'public/web/QueryParam.js',
+        'public/web/id_tree.js',
+        'public/web/tree_sheet/tree_sheet_controller.js',
+        'public/web/tree_sheet/tree_sheet_helper.js',
         'web/building_saas/complementary_glj_lib/js/glj.js',
+        'web/building_saas/complementary_glj_lib/js/gljClassTree.js',
         'web/building_saas/complementary_glj_lib/js/gljComponent.js',
         'web/building_saas/complementary_glj_lib/js/components.js',
         'public/web/ztree_common.js',

+ 3 - 3
modules/bills_lib/models/bills_lib_schemas.js

@@ -37,9 +37,9 @@ let itemsSchema = mongoose.Schema({
     {versionKey: false});
 
 let billsSchema = mongoose.Schema({
-        ID: Number,
-        ParentID: Number,
-        NextSiblingID: Number,
+        ID: String,
+        ParentID: String,
+        NextSiblingID: String,
         code: String,
         name: String,
         unit: String,

+ 67 - 4
modules/complementary_glj_lib/models/gljModel.js

@@ -58,12 +58,34 @@ class GljDao {
         }
     }
     //获得用户的补充工料机和用户当前所在编办的标准工料机
-    getGljItems (stdGljLibId, userId, compilationId, callback){
+    async getGljItems (stdGljLibId, userId, compilationId, callback){
         let me = this;
         let rst = {stdGljs: [], complementaryGljs: []};
+        //批量获取异步
+       /* let functions = [];
+        let count = await stdGljModel.find({repositoryId: stdGljLibId, $or: [{deleted: null}, {deleted: false}]}).count();
+        let findCount = Math.ceil(count/500);
+        for(let i = 0, len = findCount; i < len; i++){
+            functions.push((function(flag) {
+                return function (cb) {
+                    stdGljModel.find({repositoryId: stdGljLibId, deleted: null}, cb).skip(flag).sort({ID: 1}).limit(500);
+                }
+            })(i*500));
+        }
+        async.parallel(functions,  function (err, results) {
+            if(err){
+                callback(err, null);
+            }
+            else{
+                for(let stdGljs of results){
+                    rst.stdGljs = rst.stdGljs.concat(stdGljs);
+                }
+                callback(0, rst);
+            }
+        });*/
         async.parallel([
-            function (cb) {
-                stdGljModel.find({repositoryId: stdGljLibId}, function (err, stdGljs) {
+           async function (cb) {
+               /* stdGljModel.find({repositoryId: stdGljLibId}, function (err, stdGljs) {
                     if(err){
                         cb(err);
                     }
@@ -72,7 +94,48 @@ class GljDao {
                         rst.stdGljs = stdGljs;
                         cb(null);
                     }
-                });
+                });*/
+               try{
+                   let stdGljs = [];
+                   let first = await stdGljModel.find({repositoryId: stdGljLibId}).sort({ID: 1}).limit(1);
+                   let count = await stdGljModel.find({repositoryId: stdGljLibId, $or: [{deleted: null}, {deleted: false}]}).count();
+                   let findCount = Math.ceil(count/500);
+                   let flag = first[0].ID;
+                   //let flag = 0;
+                   //批量获取,非skip
+                   for(let i = 0, len = findCount; i < len; i++){
+                       let tempStdGlj;
+                       if(i === 0){
+                           tempStdGlj = await stdGljModel.find({repositoryId: stdGljLibId, deleted: null, ID: {$gte: flag}}).sort({ID: 1}).limit(500);
+                           if(tempStdGlj.length > 0){
+                               flag = tempStdGlj[tempStdGlj.length - 1].ID;
+                           }
+                       }
+                       else {
+                           tempStdGlj = await stdGljModel.find({repositoryId: stdGljLibId, deleted: null, ID: {$gt: flag}}).sort({ID: 1}).limit(500);
+                           if(tempStdGlj.length > 0){
+                               flag = tempStdGlj[tempStdGlj.length - 1].ID;
+                           }
+                       }
+                       if(tempStdGlj){
+                           stdGljs = stdGljs.concat(tempStdGlj);
+                       }
+                   }
+               /*    for(let i = 0, len = findCount; i < len; i++){
+                       let tempStdGlj = await stdGljModel.find({repositoryId: stdGljLibId, deleted: null}).skip(flag).sort({ID: 1}).limit(500);
+                       if(tempStdGlj.length > 0){
+                           flag = flag + 500;
+                           stdGljs = stdGljs.concat(tempStdGlj);
+                       }
+                   }*/
+                   me.sortToNumber(stdGljs);
+                   rst.stdGljs = stdGljs;
+                   cb(null);
+               }
+               catch (err){
+                   cb(err);
+               }
+
             },
             function (cb) {
                 complementaryGljModel.find({userId: userId, compilationId: compilationId}, function (err, complementaryGljs) {

+ 1 - 0
modules/complementary_ration_lib/models/searchModel.js

@@ -57,6 +57,7 @@ class SearchDao{
             for(let i = 0, len = stdRations.length; i < len; i++){
                 stdRations[i]._doc.type = 'std';
             }
+            filter.userId = userId;
             let compleRations = await compleRationModel.find(filter);
             for(let i = 0, len = compleRations.length; i <len; i++){
                 compleRations[i]._doc.type = 'complementary';

+ 2 - 1
modules/glj/controllers/glj_controller.js

@@ -395,7 +395,8 @@ class GLJController extends BaseController {
             if (!copyResult) {
                 throw '复制数据失败';
             }
-
+           await ProjectModel.updateUnitFileToProject(projectId,{id:addResult.id,name:addResult.name});
+            responseData.data = addResult;
         } catch (error) {
             responseData.err = 1;
             responseData.msg = error;

+ 8 - 10
modules/glj/models/unit_price_file_model.js

@@ -7,6 +7,7 @@
  */
 import BaseModel from "../../common/base/base_model";
 import CounterModel from "./counter_model";
+const ProjectModel = require('../../pm/models/project_model').project;
 import {default as UnitPriceFileSchema, collectionName as collectionName} from "./schemas/unit_price_file";
 
 class UnitPriceFileModel extends BaseModel {
@@ -71,19 +72,16 @@ class UnitPriceFileModel extends BaseModel {
             if (isNaN(projectId) || projectId <= 0) {
                 throw '标段id有误';
             }
-            result = await this.findDataByCondition({project_id: projectId});
-
-            // 如果没有找到则新增一条记录
-            if (!result) {
-                let data = {
-                    // @todo 后续再项目中获取
-                    name: 'projectName',
-                    project_id: projectId
-                };
-                result = await this.add(data);
+
+            let unitPriceFileId =await ProjectModel.getUnitPriceFileId(projectId);
+            if (unitPriceFileId <= 0) {
+                throw '没有对应的单价文件';
             }
+            result = await this.findDataByCondition({id: unitPriceFileId});
+
         } catch (error) {
             console.log('error:' + error);
+            throw '没有对应的单价文件 '
         }
 
         return result;

+ 10 - 6
modules/glj/models/unit_price_model.js

@@ -12,6 +12,7 @@ import MixRatioModel from "./mix_ratio_model";
 import {default as UnitPriceSchema, collectionName as collectionName} from "./schemas/unit_price";
 import _ from "lodash";
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
+let decimal_facade = require('../../main/facade/decimal_facade');
 
 class UnitPriceModel extends BaseModel {
 
@@ -262,7 +263,7 @@ class UnitPriceModel extends BaseModel {
         if(mixRatioList&&mixRatioList.length>0){
             for(let m of mixRatioList){
                 if(!connectKeyMap.hasOwnProperty(m.connect_key)){//为了去重复,组成物会与其它项目同步,所以有可能重复。
-                    rList.push(await this.updateParentUnitPrice(m,data.field));
+                    rList.push(await this.updateParentUnitPrice(m,data.field,data.project_id));
                     connectKeyMap[m.connect_key]=true;
                 }
             }
@@ -270,7 +271,10 @@ class UnitPriceModel extends BaseModel {
         return rList;
     }
 
-    async updateParentUnitPrice(mixRatio,fieid){
+    async updateParentUnitPrice(mixRatio,fieid,project_id){
+        let  decimalObject =await decimal_facade.getProjectDecimal(project_id);
+        let quantity_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.quantity)?decimalObject.glj.quantity:3;
+        let price_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.unitPrice)?decimalObject.glj.unitPrice:2;
         //查找该工料机所有组成物
         let indexList = ['code','name','specs','unit','type'];
         let mixRatioModel = new MixRatioModel();
@@ -292,11 +296,11 @@ class UnitPriceModel extends BaseModel {
         let priceMap = await this.findDataByCondition(condition, {_id: 0}, false, indexList);
         let sumPrice=0;
         for(let pk in priceMap){
-            let price = parseFloat(priceMap[pk][fieid]);
-            let consumption = parseFloat(mixRatioMap[pk].consumption);
-            sumPrice +=scMathUtil.roundTo(price*consumption,-6);
+            let price = scMathUtil.roundForObj(priceMap[pk][fieid],price_decimal);
+            let consumption = scMathUtil.roundForObj(mixRatioMap[pk].consumption,quantity_decimal);
+            sumPrice +=scMathUtil.roundForObj(price*consumption,price_decimal);
         }
-        sumPrice= scMathUtil.roundTo(sumPrice,-6);
+        sumPrice= scMathUtil.roundForObj(sumPrice,-price_decimal);
         if(sumPrice<=0){
             return null;
         }

+ 33 - 0
modules/main/controllers/bills_controller.js

@@ -7,6 +7,7 @@ let ration_model = require('../models/ration');
 let ProjectsData = require('../../pm/models/project_model').project;
 let logger = require("../../../logs/log_helper").logger;
 let quantity_detail = require("../facade/quantity_detail_facade");
+let bill_detail = require("../facade/bill_facade");
 let ration_glj = mongoose.model('ration_glj');
 let ration_coe = mongoose.model('ration_coe');
 
@@ -114,6 +115,38 @@ module.exports = {
             result.message = err.message;
         }
         res.json(result);
+    },
+    getSectionInfo:async function(req, res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let sectionInfo= await bill_detail.getSectionInfo(data);
+            result.data=sectionInfo;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    },
+    reorganizeFBFX:async function(req,res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let reorganizeResult= await bill_detail.reorganizeFBFX(data);
+            result.data=reorganizeResult;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
     }
 
 };

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

@@ -3,6 +3,8 @@
  */
 var Project = require('../models/project');
 let logger = require('../../../logs/log_helper').logger;
+let project_facade = require("../facade/project_facade");
+
 //统一回调函数
 var callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
@@ -33,5 +35,37 @@ module.exports = {
                 callback(req, res, err, message, null);
             }
         });
+    },
+    markUpdateProject:async function (req,res) {
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let resultData= await project_facade.markUpdateProject(data.updateInfo,data.type);
+            result.data=resultData;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    },
+    removeProjectMark:async function(req,res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let resultData= await project_facade.removeProjectMark(data.projectID);
+            result.data=resultData;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
     }
 };

+ 1 - 0
modules/main/controllers/quantity_detail_controller.js

@@ -27,6 +27,7 @@ async function save(req, res) {
         result.error=1;
         result.message = err.message;
     }
+    console.log(result);
     res.json(result);
 }
 

+ 47 - 0
modules/main/facade/bill_facade.js

@@ -0,0 +1,47 @@
+/**
+ * Created by zhang on 2018/1/22.
+ */
+let model = require("../../bills_lib/models/bills_lib_model");
+let Bills = model.billsMod;
+let _ = require("lodash");
+module.exports={
+   getSectionInfo : async function (data) {
+        let conditions=[];
+        let fxList=[];
+        let sectionInfo ={};
+        for(let libID in data){
+            let codes=[];
+            let temp={};
+            codes= _.keys(data[libID]);
+            temp['billsLibId']=libID;
+            temp['code'] = {"$in": codes};
+            conditions.push(temp);
+        }
+        if(conditions.length>0){
+            fxList = await Bills.find({"$or":conditions});
+        }
+        if(fxList.length>0){
+            let sectionIDs = {};
+            for(let f of fxList){
+                if(f._doc.sectionInfo){
+                    f._doc.sectionInfo.first?sectionIDs[f._doc.sectionInfo.first]=true:"";
+                    f._doc.sectionInfo.second?sectionIDs[f._doc.sectionInfo.second]=true:"";
+                    f._doc.sectionInfo.third?sectionIDs[f._doc.sectionInfo.third]=true:"";
+                }
+            }
+            let IDList = _.keys(sectionIDs);
+            let sectionList = await Bills.find({'ID':{'$in':IDList}});
+            let sectionMap = _.mapKeys(sectionList,'ID');
+            let fxMap =  _.mapKeys(fxList,'code');
+            sectionInfo={
+                fxMap:fxMap,
+                sectionMap :sectionMap
+            }
+            return sectionInfo;
+        }
+        return null;
+    },
+    reorganizeFBFX:async function(data){
+        console.log(data);
+    }
+}

+ 1 - 0
modules/main/facade/calc_program_facade.js

@@ -92,6 +92,7 @@ function save (user_id, datas, callback) {
     projectCalcProgramsModel.update({"projectID": 553}, {"libName":"goo—test"}, callback(null, returnData));
 }
 
+// saveCalcItem({projectID: 597, templatesID: 4, calcItem: calcItem})
 function saveCalcItem(dataObj, callback) {
     dataObj=JSON.parse(dataObj);
     projectCalcProgramsModel.findOne({projectID: dataObj.projectID}, function (err, data) {

+ 50 - 0
modules/main/facade/project_facade.js

@@ -0,0 +1,50 @@
+/**
+ * Created by zhang on 2018/1/26.
+ */
+let  projectsModel = require("../../pm/models/project_schema");
+
+module.exports = {
+    markUpdateProject:markUpdateProject,
+    removeProjectMark:removeProjectMark
+};
+
+//data = {feeRateID:111111,projectID:1245}; type = feeRate
+async function markUpdateProject(data,type) {
+    let tasks=[];
+    let query = {deleteInfo:null};
+    let result = null;
+    if(type=="feeRate"){//更改了费率
+        query['property.feeFile.id'] = data.feeRateID;
+    }
+    if(type=="unitFile"){//更改了单价文件
+        query['property.unitPriceFile.id'] = data.unitFileID;//unitPriceFile
+    }
+    let projects =await projectsModel.find(query);
+    for(let p of projects){
+        if(p.ID!=data.projectID){//当前项目不用更新
+            tasks.push(generateMarkTask(type,p.ID));
+        }
+    }
+    if(tasks.length>0){
+        result = await projectsModel.bulkWrite(tasks);
+    }
+    return result;
+}
+
+async function removeProjectMark(projectID) {
+    return await projectsModel.findOneAndUpdate({ID:projectID},{"$unset":{"changeMark":1}});
+}
+
+function generateMarkTask(value,projectID) {
+    let task = {
+        updateOne:{
+            filter:{
+                ID:projectID
+            },
+            update:{
+                changeMark:value
+            }
+        }
+    };
+    return task
+}

+ 4 - 4
modules/main/facade/quantity_detail_facade.js

@@ -45,8 +45,8 @@ async function saveQuantityDetail(datas) {
     let doc = datas;
     doc.ID = uuidV1();
     if(doc.refreshQuantity==false){ //如果选择了不替换工程量,则清空
-        await cleanQuantityDetail(doc);
-        return
+         await cleanQuantityDetail(doc);
+        return {};
     }
     if(doc.hasOwnProperty('regex')){
        return await insertRecodeWithReg(doc);
@@ -131,7 +131,7 @@ async function cleanQuantityDetail(doc) {
     }else {
         query.billID = doc.billID;
     }
-    await quantity_detail_model.deleteMany(query);
+    return await quantity_detail_model.deleteMany(query);
 }
 
 
@@ -351,7 +351,7 @@ async function summateResults (query,detailList,decimal) {
         decimal = await decimal_facade.getBillsQuantityDecimal(query.projectID,bill.unit);
        // quantity = getQuantityByUnit(quantity,bill.unit);
         quantity = scMathUtil.roundTo(quantity, -decimal);
-        doc = {quantity:quantity,isFromDetail:1};
+        doc = {quantity:quantity,isFromDetail:1,quantityEXP:'GCLMXHJ'};
         await bill_model.update({'ID':query.billID,'projectID':query.projectID,deleteInfo: null},doc);
     }
     return doc

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

@@ -22,6 +22,7 @@ let billsSchema = new Schema({
     projectID: Number,
     serialNo: Number,
     chapterID: Number,
+    billsLibId: Number,
     code: String,
     fullCode: String,
     type:{type: Number,default:4},//1 :大项费用 2:分部 3分项 4清单
@@ -29,6 +30,7 @@ let billsSchema = new Schema({
     name: String,
     unit: String,
     quantity: String, // Decimal
+    quantityEXP:String,//工程量表达式
     feeRateID:Number,
     feeRate:String,
     isFromDetail:{type: Number,default:0},//1 true 0 false
@@ -126,7 +128,7 @@ class billsModel extends baseModel {
         async.parallel(functions, function(err,result){
             let returnData = {
                 moduleName:'bills',
-                data:{}
+                data:result
             };
             callback(err, returnData);
         });

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

@@ -46,7 +46,8 @@ let rationSchema = new Schema({
     deleteInfo: deleteSchema,
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
-    from:{type: String,default:'std'},//std, cpt  来自标准、补充
+    from:{type: String,default:'std'},          //std, cpt  来自标准、补充
+    isSubcontract: Boolean,                     // 是否分包
 
     // 定额特有属性:
     libID: Number,

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

@@ -15,7 +15,8 @@ module.exports = function (app) {
     //删除单个清单,不删除子项
     billsRouter.post('/singleDelete',billsController.singleDelete);
     billsRouter.post('/multiDelete',billsController.multiDelete);
-
+    billsRouter.post('/getSectionInfo', billsController.getSectionInfo);
+    billsRouter.post('/reorganizeFBFX', billsController.reorganizeFBFX);
     app.use('/bills', billsRouter);
 };
 

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

@@ -9,6 +9,9 @@ module.exports = function (app) {
 
     projectRouter.post('/save', projectController.save);
     projectRouter.post('/getData', projectController.getData);
+    projectRouter.post('/markUpdateProject', projectController.markUpdateProject);
+    projectRouter.post('/removeProjectMark', projectController.removeProjectMark);
+
 
     app.use('/project',projectRouter);
 };

+ 59 - 2
modules/options/controllers/optionsController.js

@@ -4,7 +4,7 @@
 
 import BaseController from '../../common/base/base_controller';
 import OptionsDao from '../models/optionsModel';
-import optionsTypes from '../models/optionTypes';
+import optionSetting from '../models/optionTypes';
 
 let optionsDao = new OptionsDao();
 class OptionController extends BaseController {
@@ -13,6 +13,63 @@ class OptionController extends BaseController {
         let resJson = {error: 0, message: '', data: []};
         let user_id = req.session.sessionUser.id,
             compilation_id = req.session.sessionCompilation._id;
+        try{
+            resJson.data = await optionsDao.getOptions(user_id, compilation_id);
+            if(!resJson.data){
+                resJson.data = await optionsDao.saveOptions(user_id, compilation_id, optionSetting);
+            }
+        }
+        catch (err){
+            resJson.error = true;
+            resJson.message = '获取失败';
+            resJson.data = null;
+        }
+        res.json(resJson);
+    }
+    //获得特定选项类型的选项
+    async getOptionsByType(req, res){
+        let resJson = {error: null, message: '', data: null};
+        let user_id = req.session.sessionUser.id,
+            compilation_id = req.session.sessionCompilation._id,
+            optsType = req.body.optsType;
+        try{
+            resJson.data = await optionsDao.getOptionsByType(user_id, compilation_id, optsType);
+        }
+        catch (err){
+            resJson.error = true;
+            resJson.message = '获取失败';
+            resJson.data = null;
+        }
+        res.json(resJson);
+    }
+
+    async saveOptions(req, res){
+        let resJson = {error: 0, message: '', data: null};
+        let data = JSON.parse(req.body.data);
+        let user_id = req.session.sessionUser.id,
+            compilation_id = req.session.sessionCompilation._id,
+            optSetting = data.optSetting;
+        try{
+            resJson.data = await optionsDao.saveOptions(user_id, compilation_id, optSetting);
+        }
+        catch (err){
+            resJson.error = true;
+            resJson.message = '保存失败';
+            resJson.data = null;
+        }
+        res.json(resJson);
+    }
+}
+
+
+
+
+/*class OptionController extends BaseController {
+    //获得所有选项类型的选项
+    async getOptions(req, res){
+        let resJson = {error: 0, message: '', data: []};
+        let user_id = req.session.sessionUser.id,
+            compilation_id = req.session.sessionCompilation._id;
         let defaultOpts = {
             GENERALOPTS: {
                 rationQuanACToBillsQuan: true,//自动根据清单工程量填写定额工程量
@@ -82,6 +139,6 @@ class OptionController extends BaseController {
         }
         res.json(resJson);
     }
-}
+}*/
 
 export default OptionController;

+ 57 - 4
modules/options/models/optionTypes.js

@@ -5,9 +5,62 @@
 /*
 * 用户选项设置的选项类型,目前有常规选项
 * */
-
-const optionsTypes = {
-    GENERALOPTS: 'GENERALOPTS'//常规选项:1.自动根据清单工程量填写定额工程量 2.自动根据定额单位转换定额工程量
+const optionSetting = {
+    GENERALOPTS: {
+        rationQuanACToBillsQuan: true,//自动根据清单工程量填写定额工程量
+        rationQuanACToRationUnit: true//自动根据定额单位转换定额工程量
+    },
+    //色彩相关
+    COLOROPTS: {
+        DEFAULT: {
+            backColor: 'White',
+            foreColor: 'Black',
+            stringFont: '15px Arial',
+            numFont: '13px Arial'
+        },
+        DXFY: {
+            backColor: 'default',
+            foreColor: 'default',
+            stringFont: 'bold 15px Arial',
+            numFont: 'bold 13px Arial'
+        },
+        FB: {
+            backColor: '#C1D3E3',
+            foreColor: 'default',
+            stringFont: 'default',
+            numFont: 'default'
+        },
+        UNLEAFBILL: {
+            backColor: '#C1D3E3',
+            foreColor: 'default',
+            stringFont: 'default',
+            numFont: 'default'
+        },
+        FX: {
+            backColor: '#DAE5EE',
+            foreColor: 'default',
+            stringFont: 'default',
+            numFont: 'default'
+        },
+        UNCBBILL: {
+            backColor: '#DAE5EE',
+            foreColor: 'default',
+            stringFont: 'default',
+            numFont: 'default'
+        },
+        CBBILL: {
+            backColor: '#E5F3F2',
+            foreColor: 'default',
+            stringFont: 'default',
+            numFont: 'default'
+        },
+        ZCSB: {
+            backColor: 'default',
+            foreColor: '#4D7BFF',
+            stringFont: 'default',
+            numFont: 'default'
+        }
+    }
 };
 
-export default optionsTypes;
+export default optionSetting;

+ 29 - 1
modules/options/models/optionsModel.js

@@ -12,6 +12,34 @@ class OptionsDao {
     }
 
     async getOptionsByType(user_id, compilation_id, optsType){
+        let rst = await optionsModel.findOne({user_id: user_id, compilation_id: compilation_id});
+        if(rst){
+            return rst.options[optsType] !== undefined && rst.options[optsType] !== null ? rst.options[optsType] : null;
+        }
+    }
+
+    async saveOptions(user_id, compilation_id, optSetting){
+        let optionsData = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
+        if(optionsData.length === 0){
+            await optionsModel.create({user_id: user_id, compilation_id: compilation_id, options: optSetting});
+        }
+        await optionsModel.update({user_id: user_id, compilation_id: compilation_id}, optSetting);
+        let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
+        return rst.length > 0 && typeof rst[0].options !== 'undefined' ? rst[0].options : null;
+    }
+}
+
+
+
+
+/*class OptionsDao {
+    async getOptions(user_id, compilation_id){
+        let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
+        rst = rst.length > 0 && typeof rst[0].options !== 'undefined' ? rst[0].options : null;
+        return rst;
+    }
+
+    async getOptionsByType(user_id, compilation_id, optsType){
         let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
         if(rst.length > 0){
             let opts = rst[0].options;
@@ -33,6 +61,6 @@ class OptionsDao {
         let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
         return rst;
     }
-}
+}*/
 
 export default OptionsDao;

+ 10 - 1
modules/options/models/schemas.js

@@ -10,9 +10,18 @@ let Schema = mongoose.Schema;
 let optionSchema = new Schema({
     user_id: String,
     compilation_id: String,
-    options: Array
+    options: {
+        type: Schema.Types.Mixed,
+        default: {}
+    }
 }, {versionKey: false});
 
+/*let optionSchema = new Schema({
+    user_id: String,
+    compilation_id: String,
+    options: Array
+}, {versionKey: false});*/
+
 let optionsModel = mongoose.model('options', optionSchema);
 
 export default optionsModel;

+ 5 - 1
modules/pm/models/project_model.js

@@ -122,6 +122,8 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.unitPriceFile.id = addResult.id;
                 }
                 if (data.updateData.projType === projectType.tender) {
+                    //单价文件
+                    data.updateData.property.unitPriceFile.id=parseInt(data.updateData.property.unitPriceFile.id);
                     //小数位数
                     data.updateData.property.decimal = defaultDecimal;
                     //清单工程量精度
@@ -695,7 +697,9 @@ ProjectsDAO.prototype.getSummaryFees = async function (ID) {
     };
 };
 
-
+ProjectsDAO.prototype.updateUnitFileToProject=async function(projectID,unitFile){
+    return await Projects.findOneAndUpdate({'ID':projectID},{'property.unitPriceFile':unitFile});
+}
 
 
 

+ 2 - 1
modules/pm/models/project_schema.js

@@ -29,7 +29,8 @@ let ProjectSchema = new Schema({
         estimateFee: String,
         safetyFee: String,
         chargeFee: String
-    }
+    },
+    "changeMark":String//更新标记  feeRate:费率文件发生了改变,unitFile 单件文件发生了改变
 });
 
 module.exports = mongoose.model(collectionName, ProjectSchema);

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

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

+ 2 - 1
modules/pm/models/templates/schemas/bills_template.js

@@ -31,7 +31,8 @@ let BillsTemplateSchema = {
     valuationId: String,
     // 工程专业
     engineering: Number,
-    type:Number
+    type:Number,
+    calcBase: String
 };
 
 let model = mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));

+ 2 - 1
modules/ration_glj/facade/glj_calculate_facade.js

@@ -103,7 +103,7 @@ async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,noN
         if(noNeedCal==null){
             if(!glj._doc.hasOwnProperty('customQuantity')||glj.customQuantity==null||glj.customQuantity==""){
                 quantity =scMathUtil.roundTo(parseFloat(glj.rationItemQuantity),-decimal);
-                quantity =calculateAss(quantity,assList,glj);
+                quantity =scMathUtil.roundTo(calculateAss(quantity,assList,glj),-decimal);
                 quantity = calculateQuantityByCoes(quantity,coeList,glj);
             }else {
                 quantity = glj.customQuantity;
@@ -111,6 +111,7 @@ async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,noN
             }
             let customerCoe = _.last(coeList);
             if(customerCoe&&customerCoe.isAdjust==1){
+                quantity = scMathUtil.roundToString(quantity,decimal);
                 quantity = calculateQuantityByCustomerCoes(quantity,customerCoe,glj);
             }
             result.doc.quantity =scMathUtil.roundToString(quantity,decimal);

+ 20 - 5
modules/ration_glj/facade/ration_glj_facade.js

@@ -176,11 +176,14 @@ async function getInfoFromProjectGLJ(ration_glj) {
     try {
         let projectGljModel = new GLJListModel();
         let result = await projectGljModel.addList(data);
+        let typeString = result.type+"";
         ration_glj.marketPrice = result.unit_price.market_price;
         ration_glj.adjustPrice = result.unit_price.base_price;
         ration_glj.basePrice = result.unit_price.base_price;
         ration_glj.projectGLJID = result.id;
-        ration_glj.isEstimate = result.is_evaluate;
+        if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+            ration_glj.isEstimate = result.is_evaluate;
+        }
         if (result.hasOwnProperty('subList') && result.subList.length > 0) {
             ration_glj.subList = getMixRatioShowDatas(result.subList);
         }
@@ -591,12 +594,15 @@ async function addGLJ(rgList) {
     for (let g of rgList) {
         let projectGljModel = new GLJListModel();
         let result = await projectGljModel.addList(getGLJSearchInfo(g));
+        let typeString = result.type+'';
         g.marketPrice = result.unit_price.market_price;
         g.adjustPrice = result.unit_price.base_price;
         g.basePrice = result.unit_price.base_price;
         g.isAdd = result.unit_price.is_add;
         g.projectGLJID = result.id;
-        g.isEstimate = result.is_evaluate;
+        if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+            g.isEstimate = result.is_evaluate;
+        }
         g.ID = uuidV1();
         if (result.hasOwnProperty('subList') && result.subList.length > 0) {
             g.subList = getMixRatioShowDatas(result.subList);
@@ -621,6 +627,7 @@ async function replaceGLJ(data) {
     let rdata = {};
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(data));
+    let typeString = result.type+'';
     data.projectGLJID = result.id;
     let updateResult = await ration_glj.findOneAndUpdate({ID: data.ID, projectID: data.projectID}, data);//更新定额工料机
     //组装回传数据
@@ -628,7 +635,9 @@ async function replaceGLJ(data) {
     data.adjustPrice = result.unit_price.base_price;
     data.basePrice = result.unit_price.base_price;
     data.isAdd = result.unit_price.is_add;
-    data.isEstimate = result.is_evaluate;
+    if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+        data.isEstimate = result.is_evaluate;
+    }
     if (result.hasOwnProperty('subList') && result.subList.length > 0) {
         data.subList = getMixRatioShowDatas(result.subList);
     }
@@ -644,6 +653,7 @@ async function mReplaceGLJ(data) {
     let mresult = {};
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(data.doc));
+    let typeString = result.type+'';
     data.doc.projectGLJID = result.id;
     let rationList = await ration_glj.distinct('rationID', data.query);
     let updateResult = await ration_glj.update(data.query, data.doc, {multi: true});
@@ -652,7 +662,9 @@ async function mReplaceGLJ(data) {
     data.doc.adjustPrice = result.unit_price.base_price;
     data.doc.basePrice = result.unit_price.base_price;
     data.doc.isAdd = result.unit_price.is_add;
-    data.doc.isEstimate = result.is_evaluate;
+    if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+        data.doc.isEstimate = result.is_evaluate;
+    }
     if (result.hasOwnProperty('subList') && result.subList.length > 0) {
         data.doc.subList = getMixRatioShowDatas(result.subList);
     }
@@ -759,12 +771,15 @@ async function insertGLJAsRation(data) {
         let p_glj = getGLJSearchInfo(glj);
         let projectGljModel = new GLJListModel();
         let result = await projectGljModel.addList(p_glj);//逐条添加到项目工料机
+        let typeString = result.type+'';
         glj.marketPrice = result.unit_price.market_price;
         glj.adjustPrice = result.unit_price.base_price;
         glj.basePrice = result.unit_price.base_price;
         glj.isAdd = result.unit_price.is_add;
         glj.projectGLJID = result.id;
-        glj.isEstimate = result.is_evaluate;
+        if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+            glj.isEstimate = result.is_evaluate;
+        }
     }
     await ration.insertMany(gljList);
     console.log(gljList);

+ 2 - 1
modules/ration_glj/models/ration_glj_temp.js

@@ -139,12 +139,13 @@ var rationItemSchema = mongoose.Schema({
 mongoose.model("std_ration_lib_ration_items",rationItemSchema, "std_ration_lib_ration_items");
 
 let billsSchema = new Schema({
-    ID: Number,
+    ID: String,
     ParentID: Number,
     NextSiblingID: Number,
     projectID: Number,
     serialNo: Number,
     chapterID: Number,
+    billsLibId: Number,//清单库ID
     code: String,
     fullCode: String,
     type:Number,

+ 8 - 0
public/web/common_util.js

@@ -27,3 +27,11 @@ function mergeArr(arr1, arr2){
         };
     }
 };
+
+// 判断 sub 是否是 arr 的子数组。
+function isSubArr(sub, arr){
+    for(var i = 0, len = sub.length; i < len; i++){
+        if(arr.indexOf(sub[i]) == -1) return false;
+    }
+    return true;
+};

+ 14 - 10
public/web/id_tree.js

@@ -88,8 +88,12 @@ var idTree = {
                 var pre, next, i;
                 if (nodes.length === 0) { return; }
                 if (arguments.length === 4) {
-                    pre = (iIndex <= 0 || iIndex > children.length) ? null : children[iIndex - 1];
-                    next = pre ? pre.nextSibling : null;
+                    pre = (iIndex <= 0 || iIndex > children.length) ? null : children[iIndex-1];
+                    if(pre==null){
+                        next = iIndex==0?children[0]:null;
+                    }else {
+                        next = pre.nextSibling;
+                    }
                 } else if (arguments.length === 3) {
                     pre = children.length === 0 ? null : children[children.length - 1];
                     next = null;
@@ -422,7 +426,7 @@ var idTree = {
             }
         })();
         Tree.prototype.newNodeID = function () {
-            if (this.rangeNodeID() === -1) {
+            if (this.rangeNodeID() == -1) {
                 return this.maxNodeID() + 1;
             } else {
                 if (this.maxNodeID() < this.rangeNodeID()) {
@@ -460,7 +464,7 @@ var idTree = {
             // set parent by pid, set nextSibling by nid
             datas.forEach(function (data) {
                 node = that.nodes[prefix + data[that.setting.id]];
-                if (data[that.setting.pid] === that.setting.rootId) {
+                if (data[that.setting.pid] == that.setting.rootId) {
                     that.roots.push(node);
                 } else {
                     parent = that.nodes[prefix + data[that.setting.pid]];
@@ -500,8 +504,8 @@ var idTree = {
 
         Tree.prototype.insert = function (parentID, nextSiblingID) {
             var newID = this.newNodeID(), node = null, data = {};
-            var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID === -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
+            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
             if (newID !== -1) {
                 data = {};
                 data[this.setting.id] = newID;
@@ -522,8 +526,8 @@ var idTree = {
         Tree.prototype.getInsertData = function (parentID, nextSiblingID, uid = null) {
             var data = [];
             var newID = uid ? uuid.v1() : this.newNodeID();
-            var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID === -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
+            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
             if (newID != -1) {
                 data.push({type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId)});
 
@@ -538,8 +542,8 @@ var idTree = {
             return data;
         };
         Tree.prototype.insertByData = function (data, parentID, nextSiblingID, uid = null) {
-            var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID === -1 ? null : this.nodes[this.prefix + nextSiblingID];
+            var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
+            var nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
             var node = this.nodes[this.prefix + data[this.setting.id]];
             if (node) {
                 return node;

+ 38 - 6
public/web/socket/connection.js

@@ -2,25 +2,57 @@
  * Created by zhangweicheng on 2017/8/7.
  */
 socketObject={
+  roomInfo : null,
   connect:function () {
       // 连接socket服务器
       var hostName = window.location.hostname;
+      let me = this;
       socket = io('http://'+hostName+':3300');
       socket.on('connect', function () {
-
-          var roomID = projectObj.project.FeeRate.getActivateFeeRateFileID();
-          socket.emit('join', roomID);
+          me.roomInfo={
+              feeRate:me.getFeeRateRoomID(),
+              unitFile:me.getUnitFileRoomID()
+          }
+          socket.emit('join', {name:'feeRate',value:me.getFeeRateRoomID()});
+          socket.emit('join', {name:'unitFile',value:me.getUnitFileRoomID()});
           console.log('连接成功');
       });
 
       socket.on('feeRateChange', function(data) {
           //data = JSON.parse(data);
 
-          $("#message").html('费率文件已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载</a>');
+          $("#message").html('费率文件已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
           $("#notify").show();
           //alert('费率文件已经修改,请刷新页面');
           //window.location.reload();
-      })
-
+      });
+      socket.on('unitFileChange', function (data) {
+          data = JSON.parse(data);
+          /*console.log(data);
+          if (data.newValue === undefined) {
+              return false;
+          }*/
+          $("#message").html('市场单价已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+          $("#notify").show();
+      });
+      socket.on('changeFileNotify', function (data) {//收到文件改变的消息
+          if(data.projectID==projectObj.project.ID()){//如果是同个项目,则给出提示,否则忽略
+                let preString ="";
+                if(data.name=='feeRate'){
+                    preString = "费率文件";
+                }
+                if(data.name=='unitFile'){
+                    preString = "单价文件";
+                }
+              $("#message").html(preString+'已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+              $("#notify").show();
+          }
+      });
+  },
+  getFeeRateRoomID:function (){
+      return  projectObj.project.FeeRate.getActivateFeeRateFileID();
+  },
+  getUnitFileRoomID:function () {
+      return projectObj.project.projectGLJ.datas.constData.roomId?projectObj.project.projectGLJ.datas.constData.roomId:roomId;
   }
 }

+ 1 - 1
public/web/tree_sheet/tree_sheet_controller.js

@@ -67,6 +67,7 @@ var TREE_SHEET_CONTROLLER = {
                         }
                         that.sheet.deleteRows(sels[0].row, rowCount);
                         that.setTreeSelected(that.tree.items[sels[0].row]);
+                        that.sheet.setSelection(sels[0].row,sels[0].col,1,sels[0].colCount);
                     });
                     cbTools.refreshFormulaNodes();
                 }
@@ -96,7 +97,6 @@ var TREE_SHEET_CONTROLLER = {
                     cbTools.refreshFormulaNodes();
                 }
             }
-
         };
         controller.prototype.upLevel = function () {
             var that = this;

+ 34 - 25
public/web/tree_sheet/tree_sheet_helper.js

@@ -47,29 +47,31 @@ var TREE_SHEET_HELPER = {
         return style;
     },
     loadSheetHeader: function (setting, sheet) {
-        if (setting.frozenCols) {
-            sheet.frozenColumnCount(setting.frozenCols);
-        }
-        sheet.setColumnCount(setting.cols.length);
-        sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
-        setting.headRowHeight.forEach(function (rowHeight, index) {
-            sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
-        });
-        setting.cols.forEach(function (col, index) {
-            var i, iRow = 0, cell;
-            for (i = 0; i < col.head.spanCols.length; i++) {
-                if (col.head.spanCols[i] !== 0) {
-                    cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
-                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
-                }
-                if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
-                    sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
-                }
-                iRow += col.head.spanRows[i];
-            };
-            sheet.setColumnWidth(index, col.width);
-            sheet.setColumnVisible(index, col.visible && true);
-        });
+        this.massOperationSheet(sheet, function () {
+            if (setting.frozenCols) {
+                sheet.frozenColumnCount(setting.frozenCols);
+            }
+            sheet.setColumnCount(setting.cols.length);
+            sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
+            setting.headRowHeight.forEach(function (rowHeight, index) {
+                sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
+            });
+            setting.cols.forEach(function (col, index) {
+                var i, iRow = 0, cell;
+                for (i = 0; i < col.head.spanCols.length; i++) {
+                    if (col.head.spanCols[i] !== 0) {
+                        cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
+                        cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
+                    }
+                    if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                        sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
+                    }
+                    iRow += col.head.spanRows[i];
+                };
+                sheet.setColumnWidth(index, col.width);
+                sheet.setColumnVisible(index, col.visible && true);
+            });
+        });      
     },
     protectdSheet: function (sheet) {
         var option = {
@@ -101,10 +103,17 @@ var TREE_SHEET_HELPER = {
     },
     refreshTreeNodeData: function (setting, sheet, nodes, recursive) {
         nodes.forEach(function (node) {
+            let iRow = node.serialNo();
+            let nodeStyle = projectObj.getNodeColorStyle(node);
+            if(nodeStyle){
+                sheet.setStyle(iRow, -1, nodeStyle);
+            }
             setting.cols.forEach(function (colSetting, iCol) {
-                var iRow = node.serialNo();
                 var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
-
+                let boldFontStyle = projectObj.getBoldFontStyle(node, colSetting);
+                if(boldFontStyle){
+                    sheet.setStyle(iRow, iCol, boldFontStyle);
+                }
                 // var getFieldText = function () {
                 //     var fields = colSetting.data.field.split('.');
                 //     var validField = fields.reduce(function (field1, field2) {

+ 12 - 7
socket.js

@@ -11,25 +11,30 @@ const socketIO = socket(3300);
 
 // socket.io相关操作
 socketIO.on('connection', function(socket) {
-    let roomId = '';
+    let roomInfo = {};
     console.log("new connection");
     // 加入房间
     socket.on('join', function(data) {
-        roomId = data;
-        socket.join(data);
+        roomInfo[data.name] = data.value;
+        socket.join(data.value);
     });
 
 
     // 数据更改通知
-    socket.on('dataNotify', function(data) {
-        socket.broadcast.to(roomId).emit('dataChange', data);
+    socket.on('unitFileChangeNotify', function(data) {
+        console.log(roomInfo);
+        socket.broadcast.to(roomInfo['unitFile']).emit('unitFileChange', data);
     });
     socket.on('feeRateChangeNotify', function(data) {
-        socket.broadcast.to(data).emit('feeRateChange', data);
+        socket.broadcast.to(roomInfo['feeRate']).emit('feeRateChange', data);
     });
-    socket.on('changeActivateFeeRate', function(data) {
+    socket.on('changeNewRoom', function(data) {
+        if(data.projectID){//如果有项目ID,则通知同一个项目在其它地方被打开的页面
+            socket.broadcast.to(data.oldRoom).emit('changeFileNotify', data);
+        }
         socket.leave(data.oldRoom);
         socket.join(data.newRoom);
+        roomInfo[data.name]=data.newRoom;
     });
 
 });

+ 15 - 11
web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html

@@ -64,20 +64,20 @@
         </div>
         <div class="content">
             <div class="container-fluid">
-              <div class="row">
-                <div class="col-lg-2 p-0">
-                  <div class="print-list">
-                    <div class="form-list">
-                      <ul id="repositoryTree" class="ztree"></ul>
+                <div class="row">
+                    <div class="col-lg-2 p-0">
+                        <div class="print-list">
+                            <div class="form-list">
+                                <div id="gljClassSpread" style="height: 100%; width: 100%;"></div>
+                            </div>
+                        </div>
                     </div>
-                  </div>
-                </div>
-                <div id="GLJListSheet" class="col-lg-7 p-0">
+                    <div id="GLJListSheet" class="col-lg-7 p-0">
 
+                    </div>
+                    <div id="gljComponentSheet" class="col-lg-3 p-0">
+                    </div>
                 </div>
-                <div id="gljComponentSheet" class="col-lg-3 p-0">
-                </div>
-              </div>
             </div>
         </div>
       </div>
@@ -194,7 +194,11 @@
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
     <script type="text/javascript" src="/public/web/QueryParam.js"></script>
+    <script type="text/javascript" src="/public/web/id_tree.js"></script>
+    <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
+    <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/glj.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/gljClassTree.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/gljComponent.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/components.js"></script>
     <script type="text/javascript" src="/public/web/ztree_common.js"></script>

+ 29 - 4
web/building_saas/complementary_glj_lib/js/glj.js

@@ -18,8 +18,11 @@ let pageOprObj = {
         //repositoryGljObj.getRationGljIds(gljLibId);
         repositoryGljObj.getGljDistType(function () {
             repositoryGljObj.currentRepositoryId = me.stdGljLibId;
-            repositoryGljObj.getGljTree(stdGljLibId, function () {
+           /* repositoryGljObj.getGljTree(stdGljLibId, function () {
                 repositoryGljObj.getGljItems(me.stdGljLibId, me.userId, me.compilationId);
+            });*/
+            repositoryGljObj.getGljItems(me.stdGljLibId, me.userId, me.compilationId, function () {
+                gljClassTreeObj.getGljClassTree(stdGljLibId);
             });
         });
     }
@@ -116,7 +119,7 @@ let repositoryGljObj = {
             }
         });
     },
-    getGljItems: function(stdGljLibId, userId, compilationId) {
+    getGljItems: function(stdGljLibId, userId, compilationId, callback) {
         let me = this;
         CommonAjax.post('complementartGlj/api/getGljItems', {stdGljLibId: stdGljLibId, userId: userId, compilationId: compilationId}, function (rstData) {
             me.stdGljList = rstData.stdGljs;
@@ -125,12 +128,15 @@ let repositoryGljObj = {
             me.sortGlj(me.stdGljList);
             me.setProp('isStd', true, me.stdGljList);
             me.sortGlj(me.complementaryGljList);
-            let rootNode = me.treeObj.getNodes()[0];
+            if(callback){
+                callback();
+            }
+         /*   let rootNode = me.treeObj.getNodes()[0];
             if(rootNode && rootNode.isParent && rootNode.isFirstNode){
                 componentOprObj.rootNode = rootNode;
                 me.treeObj.selectNode(rootNode);
                 gljTypeTreeOprObj.onClick(null, 'repositoryTree', rootNode);
-            }
+            }*/
         });
     },
     showGljItems: function(data, type) {
@@ -1048,6 +1054,25 @@ let repositoryGljObj = {
         }
         //allgljs
     },
+    updateParentNodeIds: function (nodes, caller) {
+        let private_build_parentNodeIds = function(pNodeId, nodesArr){
+            let rst = [];
+            for (let i = 0; i < nodesArr.length; i++) {
+                if (nodesArr[i].children.length > 0) {
+                    rst = rst.concat(private_build_parentNodeIds(nodesArr[i].data.ID, nodesArr[i].children));
+                } else {
+                    rst.push(nodesArr[i].data.ID);
+                }
+            }
+            if (pNodeId && rst.length > 0) {
+                caller.parentNodeIds["_pNodeId_" + pNodeId] = rst;
+            }
+            return rst;
+        };
+        if (caller.parentNodeIds) {
+            private_build_parentNodeIds(null, nodes);
+        }
+    },
     setProp: function (prop, value, gljList) {
         let me = this;
         for(let i = 0, len = gljList.length; i < len; i++){

+ 180 - 0
web/building_saas/complementary_glj_lib/js/gljClassTree.js

@@ -0,0 +1,180 @@
+/**
+ * Created by Zhong on 2018/1/16.
+ */
+let gljClassTreeObj = {
+    cache: null,//ref to tree.items
+    tree: null,
+    controller: null,
+    workBook: null,
+    sheet: null,
+    setting: {
+        sheet: {
+            cols:[
+                {
+                    head: {
+                        titleNames: ['名称'],
+                        spanCols: [1],
+                        spanRows: [2],
+                        vAlign: [1, 1],
+                        hAlign: [1, 1],
+                        font: 'Arial'
+                    },
+                    data: {
+                        field: 'Name',
+                        vAlign: 1,
+                        hAlign: 0,
+                        font: 'Arial'
+                    },
+                    width: 400
+                }
+            ],
+            headRows: 1,
+            headRowHeight: [47],
+            emptyRows: 0,
+            treeCol: 0
+        },
+        tree: {
+            id: 'ID',
+            pid: 'ParentID',
+            nid: 'NextSiblingID',
+            rootId: -1
+        },
+        options: {
+            tabStripVisible:  false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        }
+    },
+
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isFunc: function (v) {
+        return this.isDef(v) && typeof v === 'function';
+    },
+    //sheet things
+    setOptions: function (workbook, opts) {
+        for(let opt in opts){
+            workbook.options[opt] = opts[opt];
+        }
+    },
+
+    renderFunc: function (sheet, func) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        if(this.isFunc(func)){
+            func();
+        }
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+
+    buildSheet: function () {
+        if(!this.isDef(this.workBook)){
+            this.workBook = new GC.Spread.Sheets.Workbook($('#gljClassSpread')[0], {sheetCount: 1});
+            this.sheet = this.workBook.getActiveSheet();
+            this.setOptions(this.workBook, this.setting.options);
+            this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
+            this.bindEvents(this.sheet);
+        }
+    },
+
+    bindEvents: function (sheet) {
+        let me = gljClassTreeObj;
+        const Events = GC.Spread.Sheets.Events;
+        sheet.bind(Events.SelectionChanging, me.onSelectionChanged);
+        sheet.bind(Events.EditStarting, me.onEditStarting);
+        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
+    },
+
+    onSelectionChanged: function (sender, info) {
+        let me = gljClassTreeObj;
+        if(info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
+            let row = info.newSelections[0].row;
+            let node = me.cache[row];
+            me.initSelection(node);
+        }
+    },
+
+    onEditStarting: function (sender, args) {
+        args.cancel = true;
+    },
+
+    onClipboardPasting: function (sender, info) {
+        info.cancel = true;
+    },
+
+    getGljClassTree: function (gljLibId, callback) {
+        let me = gljClassTreeObj;
+        let re = repositoryGljObj;
+        let url = 'complementartGlj/api/getGljTree';
+        let postData = {gljLibId: gljLibId};
+        let sucFunc = function (rstData) {
+            zTreeHelper.createTree(rstData, componentSetting, "componentTree", componentOprObj);
+            let rootNode = componentOprObj.treeObj.getNodes()[0];
+            if(rootNode && rootNode.isParent && rootNode.isFirstNode){
+                componentOprObj.rootNode = rootNode;
+            }
+            if (rstData && rstData.length > 0) {
+                me.gljCurTypeId = rstData[0].ID;
+            }
+            //init
+            me.buildSheet();
+            me.initTree(rstData);
+            me.cache = me.tree.items;
+            re.updateParentNodeIds(me.cache, re);
+            me.initController(me.tree, me.sheet, me.setting.sheet);
+            me.controller.showTreeData();
+            me.sheet.setFormatter(-1, 0, '@');
+            me.initSelection(me.tree.selected);
+            if(callback){
+                callback();
+            }
+        };
+        let errFunc = function () {
+
+        };
+        CommonAjax.post(url, postData, sucFunc, errFunc);
+    },
+
+    initTree: function (datas) {
+        this.tree = idTree.createNew(this.setting.tree);
+        this.tree.loadDatas(datas);
+        this.tree.selected = this.tree.items.length > 0 ? this.tree.items[0] : null;
+    },
+
+    initController: function (tree, sheet, setting) {
+        this.controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting);
+    },
+
+    gljClassTreeAjax: function (postData, scFunc, errFunc) {
+        CommonAjax.post('api/updateNodes', {updateData: postData, lastOpr: userAccount}, scFunc, errFunc);
+    },
+    //模仿默认点击
+    initSelection: function (node) {
+        let me = this,
+            re = repositoryGljObj,
+            that = gljComponentOprObj;
+        if(!re.isDef(node)){
+            return;
+        }
+
+        let gljTypeId = node.data.ID;
+        re.gljCurTypeId = node.data.ID;
+        re.addGljObj = null;
+        sheetOpr.cleanSheet(that.workBook.getSheet(0), that.setting, 5);
+        if (re.parentNodeIds["_pNodeId_" + gljTypeId]) {
+            re.currentOprParent = 1;
+            re.currentCache = re.getParentCache(re.parentNodeIds["_pNodeId_" + gljTypeId]);
+            re.workBook.getSheet(0).setRowCount(re.currentCache.length);
+        } else {
+            re.currentOprParent = 0;
+            re.currentCache = re.getCache();
+        }
+        re.showGljItems(re.complementaryGljList, gljTypeId);
+        me.workBook.focus(true);
+    }
+}

+ 1 - 1
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -498,7 +498,7 @@ let gljComponentOprObj = {
         let me = gljComponentOprObj, gljBasePrc = 0;
         for(let i = 0; i < component.length; i++){
             let roundBasePrc = scMathUtil.roundTo(parseFloat(component[i].basePrice), -2);
-            gljBasePrc += scMathUtil.roundTo(roundBasePrc * parseFloat(component[i].consumeAmt), -2);
+            gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * parseFloat(component[i].consumeAmt), -2) + gljBasePrc, -2);
         }
         return gljBasePrc;
     }

+ 1 - 1
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -430,11 +430,11 @@
         </div>
         <!-- JS. -->
         <script type="text/javascript" src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+        <script type="text/javascript" src="/lib/jquery/jquery-3.2.1.min.js"></script>
         <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
         <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
         <!--inject:js-->
         <script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
-        <script type="text/javascript" src="/lib/jquery/jquery-3.2.1.min.js"></script>
         <script type="text/javascript" src="/lib/popper/popper.min.js"></script>
         <script type="text/javascript" src="/lib/bootstrap/bootstrap.min.js"></script>
         <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/global.js"></script>

+ 5 - 1
web/building_saas/complementary_ration_lib/js/ration_coe.js

@@ -243,12 +243,16 @@ var rationCoeOprObj = {
             ration.rationCoeList.length == 0){return;};*/
 
         var coeList = ration.rationCoeList;
+        let coeIDs = [];
+        for(let i = 0, len = coeList.length; i < len; i++){
+            coeIDs.push(coeList[i].ID);
+        }
         var curCache = me.cache["_Coe_" + ration.ID];
         if (curCache) {
             me.showCoeItems(ration.ID);
             //sheetCommonObj.lockCells(me.sheet, me.setting);
         } else if(!curCache && typeof coeList !== 'undefined' && coeList.length > 0) {
-            var data = {"libID": me.libID, "coeIDs": coeList};
+            var data = {"libID": me.libID, "coeIDs": coeIDs};
             CommonAjax.post('api/getCoeItemsByIDs', data, function (rstData) {
                 sheetCommonObj.cleanData(me.sheet, me.setting, -1);
                 var tempResult = [];

+ 3 - 0
web/building_saas/css/main.css

@@ -334,4 +334,7 @@ div.resize{
     background: #f7f7f9;
     width: 100%;
     cursor: s-resize;
+}
+.zlfb-check{
+    margin-left: 0;
 }

+ 4 - 2
web/building_saas/glj/js/common_spread.js

@@ -296,9 +296,11 @@ CommonSpreadJs.prototype.getActiveDataByField = function(field) {
     return result;
 };
 CommonSpreadJs.prototype.setProjectGLJDiffPrice = function (data) {
+    let projGLJ = projectObj.project.projectGLJ;
+    data.unit_price.market_price = projGLJ.getMarketPrice(data);
     if(gljOprObj.calcPriceDiff(data)==true){//是否记算价差
-        data.base_price = data.unit_price.base_price;
-        data.adjust_price = projectObj.project.projectGLJ.getAdjustPrice(data);
+        data.base_price = projGLJ.getBasePrice(data);
+        data.adjust_price = projGLJ.getAdjustPrice(data);
     }else {
         data.base_price = data.unit_price.market_price;
         data.adjust_price = data.unit_price.market_price;

+ 81 - 33
web/building_saas/glj/js/composition.js

@@ -12,45 +12,58 @@ $(document).ready(function() {
 
     // 切换tab触发refresh
     $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
-        currentTag = $(e.target).data('name');
-
-        // 获取工料机当前选中的行号
-        let projectGLJId = 0;
-        if (currentTag === "mix-ratio") {
-            if (mixRatioSpread === null) {
-                mixRatioSpread = new CompositionSpread();
-                mixRatioSpread.init(currentTag);
-                mixRatioSpread.initRightClick(currentTag);
-                mixRatioSpread.successCallback = compositionSuccess;
-            }
+        let tagName = $(e.target).data('name');
+        if(tagName=='tab_gongliaoji'&&(currentTag!=undefined||currentTag!='')){
+            refreshSheetView();
+        }else if(tagName){
+            currentTag = $(e.target).data('name');
+            refreshSheetView();
+        }
 
-            // 筛选数据显示(显示混凝土、砂浆、配合比)
-            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,GLJTypeConst.MAIN_MATERIAL]);
+        function refreshSheetView() {
+            // 获取工料机当前选中的行号
+            let projectGLJId = 0;
+            if (currentTag === "mix-ratio") {
+                if (mixRatioSpread === null) {
+                    mixRatioSpread = new CompositionSpread();
+                    mixRatioSpread.init(currentTag);
+                    mixRatioSpread.initRightClick(currentTag);
+                    mixRatioSpread.successCallback = compositionSuccess;
+                }
 
-            projectGLJSheet.selectRow(projectGLJSpread.firstMixRatioRow);
-            projectGLJId = projectGLJSheet.getActiveDataByField('id');
+                // 筛选数据显示(显示混凝土、砂浆、配合比)
+                projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,GLJTypeConst.MAIN_MATERIAL]);
 
-            // 获取数据
-            mixRatioSpread.getRatioData(projectGLJId);
-        }
+                projectGLJSheet.selectRow(projectGLJSpread.firstMixRatioRow);
+                projectGLJId = projectGLJSheet.getActiveDataByField('id');
 
-        if (currentTag === "machine") {
-            if (machineSpread === null) {
-                machineSpread = new CompositionSpread();
-                machineSpread.init(currentTag);
-                machineSpread.initRightClick(currentTag);
-                machineSpread.successCallback = compositionSuccess;
+                // 获取数据
+                mixRatioSpread.getRatioData(projectGLJId);
             }
 
-            // 筛选数据显示(显示普通机械)
-            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.GENERAL_MACHINE]);
-            projectGLJSheet.selectRow(projectGLJSpread.firstMachineRow);
-            projectGLJId = projectGLJSheet.getActiveDataByField('id');
+            if (currentTag === "machine") {
+                if (machineSpread === null) {
+                    machineSpread = new CompositionSpread();
+                    machineSpread.init(currentTag);
+                    machineSpread.initRightClick(currentTag);
+                    machineSpread.successCallback = compositionSuccess;
+                }
 
-            // 获取数据
-            machineSpread.getRatioData(projectGLJId);
+                // 筛选数据显示(显示普通机械)
+                projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.GENERAL_MACHINE]);
+                projectGLJSheet.selectRow(projectGLJSpread.firstMachineRow);
+                projectGLJId = projectGLJSheet.getActiveDataByField('id');
+
+                // 获取数据
+                machineSpread.getRatioData(projectGLJId);
+            }
+            if (currentTag === 'ration') {
+                projectGLJSheet.filterData('unit_price.type', []);
+            }
         }
 
+
+
     });
 
 });
@@ -68,6 +81,7 @@ function compositionSuccess(info) {
     let parentData = jsonData[row];
     let ratioData = _.find(parentData.ratio_data,{"id":info.id});
     let con_key = gljOprObj.getIndex(ratioData,gljKeyArray);
+    let updateNodes=[];
     for(let i=0;i< jsonData.length;i++){
         let tem_key = gljOprObj.getIndex(jsonData[i],gljKeyArray);
         if(con_key == tem_key){
@@ -76,11 +90,45 @@ function compositionSuccess(info) {
             projectGLJSheet.setCellByField('quantity', info.change, true,i);
         }
     }
-
+    //更新ratio 数据
+    ratioData[info.field]=info.newValue;
+    //更新组成物map里的数据
+    let p_key = gljOprObj.getIndex(parentData,gljKeyArray);
+    let m_list = projectObj.project.projectGLJ.datas.mixRatioMap[p_key];
+    let m_ratioData = _.find(m_list,{"id":info.id});
+    if(m_ratioData){
+        m_ratioData[info.field]=info.newValue;
+    }
     // 设置父级3个价格
+    parentData.unit_price.market_price =  info.parentMarketPrice;
+    parentData.unit_price.base_price =  info.parentBasePrice;
+    //更新表格
     projectGLJSheet.setCellByField('unit_price.market_price', info.parentMarketPrice, false);
-    projectGLJSheet.setCellByField('unit_price.base_price', info.parentBasePrice, false);
-    projectGLJSheet.setCellByField('adjust_price', info.parentMarketPrice, false);
+    projectGLJSheet.setCellByField('base_price', info.parentBasePrice, false);
+    projectGLJSheet.setCellByField('adjust_price', projectObj.project.projectGLJ.getAdjustPrice(parentData), false);
     // 更新组成物缓存
     projectObj.project.composition.loadData();
+    //选查找使用了父项目工料机的定额工料机
+    let ration_gljs = _.filter(projectObj.project.ration_glj.datas,{'projectGLJID':parentData.id});
+    let nodes = projectObj.project.mainTree.nodes;
+    let prefix = projectObj.project.mainTree.prefix;
+    for(let rg of ration_gljs){
+        let node = nodes[prefix+rg.rationID];
+        if(node){
+            updateNodes.push(node);
+        }
+    }
+    //或者是使用了父项目工料机的工料机类型的定额
+    let rations = _.filter(projectObj.project.Ration.datas,{'type':3,'projectGLJID':parentData.id});
+    for(let r of rations){
+        let r_node = nodes[prefix+r.ID];
+        if(r_node){
+            r_node.data.marketUnitFee=info.parentMarketPrice;
+            updateNodes.push(r_node);
+        }
+    }
+    if(updateNodes.length>0){
+        projectObj.project.calcProgram.calcRationsAndSave(updateNodes);
+    }
+    gljOprObj.refreshView();
 }

+ 1 - 0
web/building_saas/glj/js/composition_spread.js

@@ -229,6 +229,7 @@ CompositionSpread.prototype.updateConsumption = function(info, callback) {
                 alert('更改数据失败!');
             } else {
                 info.id = id;
+                info.field = field;
                 info.parentMarketPrice = parentMarketPrice;
                 info.parentBasePrice = parentBasePrice;
                 info.change = info.newValue - info.oldValue;

+ 65 - 13
web/building_saas/glj/js/project_glj.js

@@ -27,6 +27,8 @@ let otherFileData = {};
 let currentTag = '';
 let isChanging = false;
 let initPage = false;
+
+
 $(document).ready(function () {
     $('#tab_gongliaoji').on('show.bs.tab', function (e) {
         $(e.relatedTarget.hash).removeClass('active');
@@ -122,6 +124,24 @@ $(document).ready(function () {
                     $("#save-as-tips").text(msg).show();
                     return false;
                 }
+                projectObj.project.projectGLJ.loadData(function () {
+                    let projectGLJ = projectObj.project.projectGLJ;
+                    projectGLJ.loadCacheData();
+                    unitPriceFileInit();
+                    projectObj.project.calcProgram.calcAllNodesAndSave();
+                    gljOprObj.refreshView();
+                    if(socketObject.roomInfo){
+                        let data ={
+                            projectID:projectObj.project.ID(),
+                            oldRoom:socketObject.roomInfo.unitFile,
+                            newRoom:socketObject.getUnitFileRoomID(),
+                            name:'unitFile'
+                        }
+                        socket.emit('changeNewRoom',data);
+                        socketObject.roomInfo.unitFile = socketObject.getUnitFileRoomID();
+                    }
+                    $.bootstrapLoading.end();
+                });
                 $("#file-save-as-dialog").modal("hide");
             }
         });
@@ -194,6 +214,17 @@ $(document).ready(function () {
                     projectGLJ.loadCacheData();
                     unitPriceFileInit();
                     gljOprObj.refreshView();
+                    projectObj.project.calcProgram.calcAllNodesAndSave();
+                    if(socketObject.roomInfo){
+                        let data ={
+                            projectID:projectObj.project.ID(),
+                            oldRoom:socketObject.roomInfo.unitFile,
+                            newRoom:socketObject.getUnitFileRoomID(),
+                            name:'unitFile'
+                        }
+                        socket.emit('changeNewRoom',data);
+                        socketObject.roomInfo.unitFile = socketObject.getUnitFileRoomID();
+                    }
                     $.bootstrapLoading.end();
                 });
             }
@@ -240,8 +271,8 @@ function init() {
                 data.constData.ownCompositionTypes : canNotChangeTypeId;
             GLJTypeConst = data.constData.GLJTypeConst !== undefined ? JSON.parse(data.constData.GLJTypeConst) : GLJTypeConst;
 
-            // 连接socket服务器
-            socketInit();
+            // 连接socket服务器  这里改成和费率的socket统一管理了,需要在主页面打开后就连接
+           // socketInit();
 
             unitPriceFileInit();
 
@@ -260,6 +291,9 @@ function init() {
  * @return {void}
  */
 function spreadInit() {
+    if(projectGLJSheet&&projectGLJSpread){
+        projectGLJSheet.spread.destroy();
+    }
     projectGLJSpread = new ProjectGLJSpread();
     projectGLJSpread.successCallback = successTrigger;
     projectGLJSheet = projectGLJSpread.init();
@@ -285,13 +319,28 @@ function spreadInit() {
         lastRow = currentRow;
     });
 
-    // 切换tab触发refresh
+    if(currentTag){
+        if (currentTag === 'ration') {
+            projectGLJSheet.filterData('unit_price.type', []);
+        }
+        if(currentTag === "mix-ratio"){
+            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,GLJTypeConst.MAIN_MATERIAL]);
+        }
+        if(currentTag === "machine"){
+            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.GENERAL_MACHINE]);
+        }
+    }
+
+  /*  // 切换tab触发refresh
     $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        if($(e.target).data('name')==undefined){
+            return;
+        }
         currentTag = $(e.target).data('name');
         if (currentTag === 'ration') {
             projectGLJSheet.filterData('unit_price.type', []);
         }
-    });
+    });*/
 
     loadSize("glj-main", function () {
         projectGLJSpread.sheetObj.spread.refresh();
@@ -357,7 +406,7 @@ function successTrigger(field, info,id) {
 
 //更新是否暂估
 function changeIsEvaluate (id){
-    let projectGLJ = projectObj.project.projectGLJ
+    let projectGLJ = projectObj.project.projectGLJ;
     let datas = projectGLJ.datas;
     let gljList = datas.gljList;
     let glj = _.find(gljList, {'id': id});
@@ -366,13 +415,20 @@ function changeIsEvaluate (id){
         let pratioM =datas.mixRatioConnectData[con_key];//找到父key
         let conditions = [];
         if(pratioM&&pratioM.length>0){
-            for(let p_key in pratioM ){
+            for(let p_key of pratioM ){
                 conditions.push(gljOprObj.getConditionByKey(p_key));
             }
         }
         let gljs = projectGLJ.getProjectGLJs(conditions,false);
         gljs.push(glj);
         let nodes = projectGLJ.getImpactRationNodes(gljs);//取到因为改变工料机价格而受影响的定额
+        //更新对应的工料机类型的定额
+        let ration =_.find(projectObj.project.Ration.datas,{'type':rationType.gljRation,'projectGLJID':glj.id});
+        if(ration){
+            ration.isEstimate =glj.is_evaluate?1:0;
+            let ration_node = projectObj.project.mainTree.getNodeByID(ration.ID);
+            ration_node?projectObj.mainController.refreshTreeNode([ration_node]):"";
+        }
         projectObj.project.calcProgram.calcRationsAndSave(nodes);//触发计算程序
     }
 }
@@ -406,13 +462,9 @@ function socketInit() {
 function filterProjectGLJ(jsonData) {
     if (jsonData.length > 0) {
         // 不显示消耗量为0的数据
-        let tmpData = [];
-        for (let data of jsonData) {
-            if (data.quantity !== 0 && data.quantity !== '0') {
-                tmpData.push(data);
-            }
-        }
-        jsonData = tmpData;
+        jsonData= _.filter(jsonData,function (item) {
+            return item.quantity !== 0 && item.quantity !== '0'
+        })
     }
     return jsonData;
 }

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

@@ -42,7 +42,7 @@
         <div class="main-nav">
             <ul class="nav nav-tabs flex-column" role="tablist">
                 <li class="nav-item"><a class="active" data-toggle="tab" href="#zaojiashu" id="tab_zaojiashu" role="tab">造价书</a></li>
-                <li class="nav-item"><a data-toggle="tab" href="#gongliaoji" id="tab_gongliaoji" role="tab">工料机</a></li>
+                <li class="nav-item"><a data-toggle="tab" href="#gongliaoji" id="tab_gongliaoji" data-name="tab_gongliaoji" role="tab">工料机</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#fee_rates" id="tab_fee_rate" role="tab" >费率</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab">计算程序</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#reports" role="tab" id="tab_report" onclick="rptTplObj.iniPage();">报表</a></li>
@@ -57,7 +57,7 @@
                     <a href="" class="btn btn-sm" title="复制"><i class="fa fa-files-o" aria-hidden="true"></i></a>
                     <a href="" class="btn btn-sm" title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
                     <a href="" class="btn btn-sm" title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
-                    <a href="javascript:void(0)" class="btn btn-sm" id="insert" title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
+                 <!--   <a href="javascript:void(0)" class="btn btn-sm" id="insert" title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>-->
                     <a href="javascript:void(0)" class="btn btn-sm" id="delete" title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="upLevel" title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="downLevel" title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
@@ -789,6 +789,75 @@
         </div>
     </div>
 
+    <!--弹出 整理分部-->
+    <div class="modal fade" id="zlfb" 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="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" id="bill_first" >
+                        <label class="form-check-label">
+                            需要专业分部标题
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" id="bill_second" >
+                        <label class="form-check-label">
+                            需要章分部标题
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" id="bill_third" >
+                        <label class="form-check-label">
+                            需要节分部标题
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" checked disabled value="" >
+                        <label class="form-check-label">
+                            删除自定义分部标题
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" checked id="bill_resort">
+                        <label class="form-check-label">
+                            清单排序
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input zlfb-check" type="checkbox" checked id="bill_recode"  >
+                        <label class="form-check-label">
+                            清单重新编码
+                        </label>
+                    </div>
+                    <div class="card mt-3">
+                        <div class="card-body p-2">
+                            <h5 class="card-title">操作说明</h5>
+                            <p class="card-text">执行分部整理将对当前清单列表存在的清单按以上勾选项进行整理;</br>
+                                勾选“需要专业分部标题”,表示分部整理时需要添加清单专业标题;</br>
+                                勾选“需要章分部标题”,表示分部整理时需要添加章标题;</br>
+                                勾选“需要节分部标题”,表示分部整理时需要添加节标题;</br>
+                                勾选“删除自定义分部标题”,将首先删除已有自定义分部标题,然后再执行分部整理;</br>
+                                勾选“清单排序”,表示分部整理后对每个分部下的清单进行排序;</br>
+                                勾选“清单重新编码”,表示分部整理后对每个分部下的清单重新生成水流号;
+                            </p>
+                        </div>
+                    </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="zlfb_confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
         <!-- JS. -->
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
 
@@ -867,8 +936,8 @@
         <script type="text/javascript" src="/public/web/id_tree.js"></script>
         <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/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="/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>-->
         <!-- Controller -->
         <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
@@ -895,6 +964,7 @@
         <script type="text/javascript" src="/web/building_saas/main/js/views/glj_view_contextMenu.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/calc_program_view.js"></script>
         <script type="text/javascript" src='/web/building_saas/main/js/views/confirm_modal.js'></script>
+        <script type="text/javascript" src='/web/building_saas/main/js/views/zlfb_view.js'></script>
         <!--报表-->
         <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
         <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>

+ 12 - 12
web/building_saas/main/js/calc/bills_calc.js

@@ -5,14 +5,14 @@
 // const rationContent = 0, rationPrice = 1, rationPriceConverse = 2, billsPrice = 3;
 
 // sumTotalFeeFlag: sum(child.totalFee), totalFeeFlag: bills.quantity × bills.unitFee
-const sumTotalFeeFlag = 0, totalFeeFlag = 1;
+// const sumTotalFeeFlag = 0, totalFeeFlag = 1;
 // rationContentUnitFeeFlag: sum(child.unitFee * child.quantity / bills.quantity)
 // averageQtyUnitFeeFlag: sum(child.totalFee/bills.quantity)
 // billsPriceUnitFeeFlag: 根据定额计算程序
 // converseUnitFeeFalg: bills.totalFee / bills.quantity
-const rationContentUnitFeeFlag = 0, averageQtyUnitFeeFlag = 1, billsPriceUnitFeeFlag = 2, converseUnitFeeFlag = 3;
+// const rationContentUnitFeeFlag = 0, averageQtyUnitFeeFlag = 1, billsPriceUnitFeeFlag = 2, converseUnitFeeFlag = 3;
 
-let rationContentCalcFields = [
+/*let rationContentCalcFields = [
     {'type': 'common', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': totalFeeFlag},
     {'type': 'labour', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
     {'type': 'material', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
@@ -35,9 +35,9 @@ let billsPriceCalcFields = [
     {'type': 'labour', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
     {'type': 'material', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
     {'type': 'machine', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag}
-];
+];*/
 
-let nodeCalcObj = {
+/*let nodeCalcObj = {
     node: null,
     digit: 2,
     field: null,
@@ -98,9 +98,9 @@ let nodeCalcObj = {
             return 0;
         }
     }
-};
+};*/
 
-let baseCalcField = [
+/*let baseCalcField = [
     {
         ID: 1,
         // 序号
@@ -246,9 +246,9 @@ let baseCalcField = [
         // 备注
         memo: ''
     }
-];
+];*/
 
-class BillsCalcHelper {
+/*class BillsCalcHelper {
     constructor (project, calcFlag) {
         this.project = project;
         this.InitFields(project.calcFields);
@@ -269,12 +269,12 @@ class BillsCalcHelper {
 
         // 清单单价:套用定额计算程序
         // if (this.project.projSetting.billsCalcMode === billsPrice) {
-        if (this.project.property.billsCalcMode === leafBillGetFeeType.billsPrice) {
+/!*        if (this.project.property.billsCalcMode === leafBillGetFeeType.billsPrice) {
             rationCalcObj.calcGljs = this.getBillsGLjs(node);
             console.log(rationCalcObj.calcGljs);
             rationCalcObj.calcFields = rationCalcFields;
             virData = rationCalcObj.calculate();
-        }
+        }*!/
 
         for (let field of fields) {
             nodeCalcObj.field = field;
@@ -396,4 +396,4 @@ class BillsCalcHelper {
             field.tenderTotalFeeSplit = field.tenderTotalFee.split('.');
         }
     };
-}
+}*/

+ 9 - 11
web/building_saas/main/js/calc/ration_calc.js

@@ -96,15 +96,13 @@ let rationCalcFields = [
     }
 ];
 */
-"use strict";
+// let calcEvaluate = function (expr) {
+//     let exp = new Expression('');
+//     exp.Expression(expr);
+//     return exp.Evaluate();
+// }
 
-let calcEvaluate = function (expr) {
-    let exp = new Expression('');
-    exp.Expression(expr);
-    return exp.Evaluate();
-}
-
-let rationCalcFields = [
+/*let rationCalcFields = [
     {
         type: 'rationBaseLabour', code: "1.1.1", name: "定额基价人工费",
         dispExpr: "定额基价人工费", expression: "定额基价人工费", compiledExpr: "",
@@ -301,9 +299,9 @@ let rationCalcObj = {
         }
         return result;
     }
-};
+};*/
 
-class RationCalcHelper {
+/*class RationCalcHelper {
     constructor (project) {
         this.project = project;
     }
@@ -327,4 +325,4 @@ class RationCalcHelper {
             this.calculate(rationData);
         }
     };
-}
+}*/

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

@@ -104,7 +104,7 @@ ProjectController = {
     },
     addRootBill:function (project, sheetController) {//添加大项费用
         if (!project || !sheetController) { return null; }
-        this.addSpecialBill(project, sheetController,null, null,true,billType.DXFY);
+        this.addSpecialBill(project, sheetController,null, project.mainTree.selected.nextSibling,true,billType.DXFY);
     },
     addFB:function(project, sheetController) {//添加分部
         if (!project || !sheetController) { return null; }

+ 87 - 25
web/building_saas/main/js/models/bills.js

@@ -119,11 +119,10 @@ var Bills = {
 
         // 提交数据后的错误处理方法
         bills.prototype.doAfterUpdate = function(err, data){
-            // console.log(data)
+             // console.log(data)
             if(data.quantityRefresh){
                 this.refreshDatas(data,'quantity');
             }
-            $.bootstrapLoading.end();
         };
 
         bills.prototype.refreshDatas = function(data,fieldName){
@@ -205,6 +204,8 @@ var Bills = {
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
                     data.data.programID = stdBillsData.engineering;
                     data.data.type = stdBillsData.type;//插入清单类型
+                    //Vincent
+                    data.data.billsLibId = stdBillsData.billsLibId;//添加清单库ID
                     //zhong
                     newData = data.data;
                 }
@@ -279,8 +280,6 @@ var Bills = {
                 }
                 $.bootstrapLoading.start();
                 CommonAjax.post("/bills/singleDelete", {updateData:updateData,projectID:node.data.projectID,user_id:userID,ID:node.data.ID}, function () {
-                    controller.singleDelete();//删除树节点
-                    me.tree.singleDelete(node);
                     //更新缓存
                     console.log(updateNode);
                     _.remove(me.datas,{'ID':node.data.ID});
@@ -291,6 +290,8 @@ var Bills = {
                         }
                     }
                     project.calcProgram.calcAndSave(newParent);
+                    controller.singleDelete();//删除树节点
+                    me.tree.singleDelete(node.source);
                     $.bootstrapLoading.end();
                 }, function () {
                     $.bootstrapLoading.end();
@@ -404,6 +405,7 @@ var Bills = {
                 node.data.itemCharacter = stdBillsData.itemCharacter;
                 node.data.itemCharacterText = stdBillsData.itemCharacterText;
                 node.data.programID = stdBillsData.engineering;
+                node.data.billsLibId = stdBillsData.billsLibId;
             }
             updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(node.data)});
 
@@ -494,6 +496,23 @@ var Bills = {
                 }
             }
         };
+        bills.prototype.getEngineeringCostNode=function(controller){//取工程造价节点
+            let roots =  controller.tree.roots;
+            for(let root of roots){
+                if(project.Bills.isEngineeringCost(root)==true){
+                    return root;
+                }
+            }
+        };
+        bills.prototype.getFBFXNode = function (controller) {//取分部分项工程节点
+            let roots =  controller.tree.roots;
+            for(let root of roots){
+                if(isFlag(root.data)&&root.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){
+                    return root;
+                }
+            }
+        };
+
         bills.prototype.deleteSelectedNode=function(){//删除选中单行时的节点
             let controller = projectObj.mainController, project = projectObj.project;
             let selected = controller.tree.selected, parent = selected.parent;
@@ -527,6 +546,8 @@ var Bills = {
             let mainNodes = [];
             let idTreeNodes=[];
             let updateData={};
+            let includeRootNode=false;
+            let parentNodes = [];
             let selection = projectObj.mainSpread.getActiveSheet().getSelections()[0];
             for(let i =0;i<selection.rowCount;i++){
                 let tem_node = controller.tree.items[selection.row+i];
@@ -534,13 +555,13 @@ var Bills = {
                     mainTreeMap[tem_node.getID()] = tem_node;
                     mainNodes.push(tem_node);
                     if(tem_node.sourceType == project.Bills.getSourceType()){
-                        idTreeMap[tem_node.source.getID()] = tem_node;
-                        idTreeNodes.push(tem_node);
+                        idTreeMap[tem_node.source.getID()] = tem_node.source;
+                        idTreeNodes.push(tem_node.source);
                     }
                 }else {
                     this.setNodeToMapAndArray(tem_node,mainTreeMap,mainNodes);
                     if(tem_node.sourceType == project.Bills.getSourceType()){
-                        this.setNodeToMapAndArray(tem_node,idTreeMap,idTreeNodes,true);
+                        this.setNodeToMapAndArray(tem_node.source,idTreeMap,idTreeNodes);
                     }
                 }
             }
@@ -558,6 +579,12 @@ var Bills = {
                         updateBill=true;
                     }
                 }
+                if(m_node.parent==null&&includeRootNode==false){//删除的节点中包含了根节点,要重新计算工程造价,并且工程造价节点只要加入一次就行了
+                    parentNodes.push(me.getEngineeringCostNode(controller));
+                    includeRootNode=true
+                }else {
+                    m_node.parent?parentNodes.push(m_node.parent):"";
+                }
                 updateNodes.push(m_node);
                 controller.tree.getAllSubNode(m_node,updateNodes);
             }
@@ -577,45 +604,80 @@ var Bills = {
             updateData.user_id = userID;
             $.bootstrapLoading.start();
             CommonAjax.post("/bills/multiDelete", updateData, function () {
-                controller.m_delete(mainNodes);//删除树节点
-                me.tree.m_delete(idTreeNodes);
-
-              /*  //更新缓存
-                console.log(updateNode);
-                _.remove(me.datas,{'ID':node.data.ID});
-                for(let n_key in updateNode){
-                    let updateDoc =  updateData[n_key];
-                    for(let u_key in updateDoc){
-                        updateNode[n_key].data[u_key] =updateDoc[u_key];
+                let quantity_detail_datas = project.quantity_detail.datas;
+                let ration_datas = project.Ration.datas;
+                let ration_glj_datas = project.ration_glj.datas;
+                let ration_coe_datas = project.ration_coe.datas;
+                let nodes = controller.tree.nodes;
+                let prefix = controller.tree.prefix;
+                //更新缓存
+                if(updateData['bills']){//更新bills
+                    for(let b_key in updateData['bills']){
+                        if(updateData['bills'][b_key]===true){//删除清单和工程量明细
+                            _.remove(me.datas,{'ID':b_key});
+                            _.remove(quantity_detail_datas,{'billID':b_key});
+                        }else {//更新清单属性
+                            for(let p_key in updateData['bills'][b_key]){
+                                nodes[prefix+b_key].data[p_key] = updateData['bills'][b_key][p_key]
+                            }
+                        }
+                    }
+                }
+                if(updateData['ration']){
+                    for(let r_key in updateData['ration']){//定额只有删除,没有更新
+                        _.remove(ration_datas,{'ID':r_key});
+                        _.remove(quantity_detail_datas,{'rationID':r_key});
+                        _.remove(ration_glj_datas,{'rationID':r_key});
+                        _.remove(ration_coe_datas,{'rationID':r_key});
                     }
                 }
-                project.calcProgram.calcAndSave(newParent);*/
+                controller.m_delete(mainNodes);//删除树节点
+                me.tree.m_delete(idTreeNodes);
+                //重新计算
+                project.calcProgram.calcBillsAndSave(parentNodes);
                 $.bootstrapLoading.end();
             }, function () {
                 $.bootstrapLoading.end();
             });
-
-
-
         };
-        bills.prototype.setNodeToMapAndArray=function (node,map,array,billType) {
-            let nodeID = billType ==true?node.source.getID():node.getID();
+        bills.prototype.setNodeToMapAndArray=function (node,map,array) {
+            let nodeID = node.getID();
             if(map[nodeID]==undefined||map[nodeID]==null){
                 newMap(node,node.parent,map,array)
             }
             function newMap(node,parent,map,array) {
-                let nodeID = billType ==true?node.source.getID():node.getID();
+                let nodeID =node.getID();
                 if(parent==null){//说明已经是最顶层了
                     map[nodeID]=node;
                     array.push(node);
                 }else {
-                    let parentID = billType == true?parent.source.getID():parent.getID();
+                    let parentID = parent.getID();
                     if(map[parentID]==undefined||map[parentID]==null){
                         newMap(node,parent.parent,map,array);
                     }
                 }
             }
         };
+        bills.prototype.deleteAllFBNodes = function(){
+            let controller = projectObj.mainController, project = projectObj.project;
+            let Bill = project.Bills;
+            let FBFX = Bill.getFBFXNode(controller);//取分部分项工程节点;
+            let deleteRootNodes = _.clone(FBFX.children);
+            let deleteRootNodes_id = _.clone(FBFX.source.children);
+            let sels = controller.sheet.getSelections();
+            controller.tree.m_delete(deleteRootNodes);
+            this.tree.m_delete(deleteRootNodes_id);
+            TREE_SHEET_HELPER.massOperationSheet(controller.sheet, function () {
+                let rowCount = 0;
+                for(let node of deleteRootNodes){
+                    rowCount = rowCount+node.posterityCount() + 1;
+                }
+                controller.sheet.deleteRows(1, rowCount);
+                let index = sels[0]?sels[0].row:1;
+                controller.setTreeSelected(controller.tree.items[1]);
+            });
+            cbTools.refreshFormulaNodes();
+        };
         return new bills(project);
     }
 };

+ 10 - 3
web/building_saas/main/js/models/cache_tree.js

@@ -76,8 +76,12 @@ var cacheTree = {
                 var pre, next, i;
                 if (nodes.length === 0) { return; }
                 if (arguments.length === 4) {
-                    pre = (iIndex <= 0 || iIndex > children.length) ? null : children[iIndex - 1];
-                    next = pre ? pre.nextSibling : null;
+                    pre = (iIndex <=0 || iIndex > children.length) ? null : children[iIndex-1];
+                    if(pre==null){
+                        next = iIndex==0?children[0]:null;
+                    }else {
+                        next = pre.nextSibling;
+                    }
                 } else if (arguments.length === 3) {
                     pre = children.length === 0 ? null : children[children.length - 1];
                     next = null;
@@ -440,7 +444,10 @@ var cacheTree = {
               this.getAllSubNode(c,nodeArray);
           }
         };
-        
+        Tree.prototype.getNodeByID = function (ID) {
+          let node = this.nodes[this.prefix+ID];
+          return node;
+        };
         return new Tree(owner);
     }
 };

+ 1 - 6
web/building_saas/main/js/models/calc_base.js

@@ -23,12 +23,7 @@ let cbTools = {
         return r;
     },
     findBill: function (fixedFlag) {
-        let bills = projectObj.project.Bills.datas;
-        for(let i = 0, len = bills.length; i < len; i++){
-            if(bills[i].flagsIndex && bills[i].flagsIndex.fixed && bills[i].flagsIndex.fixed.flag && bills[i].flagsIndex.fixed.flag === fixedFlag){
-                return bills[i];
-            }
-        }
+        return this.isDef(calcBase.fixedBills[fixedFlag]) ? calcBase.fixedBills[fixedFlag]['bill'] : null;
     },
     //通过行获取根节点清单
     getBillByRow: function (items, row) {

File diff suppressed because it is too large
+ 598 - 471
web/building_saas/main/js/models/calc_program.js


+ 24 - 5
web/building_saas/main/js/models/fee_rate.js

@@ -14,7 +14,6 @@ var FeeRate = {
         };
         FeeRate.prototype.loadData = function (datas) {
             this.datas = datas;
-            socketObject.connect();
         };
         FeeRate.prototype.backupDatas=function () {
           this.datasBackup = _.cloneDeep(this.datas);
@@ -192,10 +191,11 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
-            project.calcProgram.calcAllNodes(calcAllType.catBills);
+            project.calcProgram.calcAllNodesAndSave(calcAllType.catBills);
+            project.markUpdateProject({projectID:project.ID(),feeRateID:this.getActivateFeeRateFileID()},"feeRate");
             socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
         };
-        FeeRate.prototype.onFeeRateFileChange=function () {
+        FeeRate.prototype.onFeeRateFileChange=function () {//整个费率文件换了,原费率文件内容不变
             this.refreshCalProgramWhenFeeFileChange();
             this.refreshBillsWhenFeeFileChange();
             var node = project.mainTree.selected;
@@ -204,8 +204,23 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
-            project.calcProgram.calcAllNodes(calcAllType.catBills);
-            socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
+            project.calcProgram.calcAllNodesAndSave(calcAllType.catBills);
+            if(socketObject.roomInfo){
+                //判断费率文件ID是否改变了
+                if(socketObject.roomInfo.feeRate == this.getActivateFeeRateFileID()){//如果没变,则是重选了标准
+                    socket.emit('feeRateChangeNotify', socketObject.roomInfo.feeRate);
+                }else {
+                    let data ={
+                        projectID:project.ID(),
+                        oldRoom:socketObject.roomInfo.feeRate,
+                        newRoom:this.getActivateFeeRateFileID(),
+                        name:'feeRate'
+                    }
+                    socket.emit('changeNewRoom',data);
+                    socketObject.roomInfo.feeRate = this.getActivateFeeRateFileID();
+                }
+            }
+
         };
 
         FeeRate.prototype.refreshBillsWhenFeeFileChange=function(){
@@ -285,6 +300,7 @@ var FeeRate = {
                     me.datas.libName=data.libName;
                     me.datas.feeRateID=data.feeRateID;
                     me.datas.rates=data.rates;
+                    projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),feeRateID:me.getActivateFeeRateFileID()},'feeRate');
                     me.onFeeRateFileChange();
                     callback();
                 }
@@ -380,10 +396,13 @@ var FeeRate = {
                 var data={'projectID': projectObj.project.ID(),'templatesID': editInfo.template.ID,'calcItem': editInfo.calcItem};
                 calcProgramManage.saveCalcItem(data,function (result) {
                     project.calcProgram.compileAllTemps();
+                    project.calcProgram.calcAllNodesAndSave();
                     calcProgramManage.refreshDetailSheet();
+                    $.bootstrapLoading.end();
                 })
             }else {
                 calcProgramManage.refreshDetailSheet();
+                $.bootstrapLoading.end();
             }
         };
         FeeRate.prototype.updateFeeRateByCalc=function (rate,value) {

+ 53 - 8
web/building_saas/main/js/models/main_consts.js

@@ -45,7 +45,32 @@ const gljType = {
     // 设备
     EQUIPMENT: 5
 };
-
+// 计算基数 [定额基价材料费] 要用到的材料类型。
+const baseMaterialTypes = [
+    gljType.GENERAL_MATERIAL,
+    gljType.CONCRETE,
+    gljType.MORTAR,
+    gljType.MIX_RATIO,
+    gljType.COMMERCIAL_CONCRETE,
+    gljType.COMMERCIAL_MORTAR
+];
+// 全部材料类型。用于暂估等 (多了主材和设备)
+const allMaterialTypes = [
+    gljType.GENERAL_MATERIAL,
+    gljType.CONCRETE,
+    gljType.MORTAR,
+    gljType.MIX_RATIO,
+    gljType.COMMERCIAL_CONCRETE,
+    gljType.COMMERCIAL_MORTAR,
+    gljType.MAIN_MATERIAL,
+    gljType.EQUIPMENT
+];
+// 会有组成物的材料
+const compositionTypes = [
+    gljType.MAIN_MATERIAL,
+    gljType.CONCRETE,
+    gljType.MORTAR,
+    gljType.MIX_RATIO];
 const notEditType = [
     gljType.CONCRETE,
     gljType.MORTAR,
@@ -75,15 +100,20 @@ const treeNodeCalcType = {
     ctGatherRationsFees: 3,     // 汇总定额的各个费
     ctGatherBillsFees: 4,       // 汇总清单的各个费
     ctCalcBaseValue: 5,
-    ctCommonUnitFee: 6
+    ctNull: 6
+    // ctCommonUnitFee: 6       // 树结点的手工输入综合单价的方式已废弃,现综合单价只读,引入市场单价。
 };
-
 const calcAllType = {
     catAll: 'all',
     catBills: 'bills',
     catRations: 'ration'
 };
-
+const priceTypes = {
+    ptBasePrice: 1,
+    ptAdjustPrice: 2,
+    ptMarketPrice: 3,
+    ptDiffPrice: 4
+};
 const subSheetIndex = {
     ssiRationGLJ: 0,
     ssiRationCoe: 1,
@@ -93,7 +123,6 @@ const subSheetIndex = {
     ssiMemo: 5,
     ssiFeature: 6
 };
-
 const volumePriceMaps = {
     "量人": gljType.LABOUR,
     "量材": gljType.GENERAL_MATERIAL,
@@ -113,20 +142,17 @@ const volumePriceMaps = {
     4: "量主",
     5: "量设"
 };
-
 const rationType = {
     ration: 1,
     volumePrice: 2,
     gljRation: 3
 };
-
 const leafBillGetFeeType = {
     rationContent: 0,
     rationPriceConverse: 1,
     rationPrice: 2,
     billsPrice: 3
 };
-
 const zanguCalcType = {
     common: 0,
     gatherMaterial: 1
@@ -189,3 +215,22 @@ const billText = {
     3:'分项',
     4:'清单'
 };
+
+const cpFeeTypes = [
+    {type: 'direct', name: '直接费'},
+    {type: 'labour', name: '人工费'},
+    {type: 'material', name: '材料费'},
+    {type: 'machine', name: '机械费'},
+    {type: 'mainMaterial', name: '主材费'},
+    {type: 'equipment', name: '设备费'},
+    {type: 'manage', name: '企业管理费'},
+    {type: 'profit', name: '利润'},
+    {type: 'risk', name: '风险费'},
+    {type: 'labourDiff', name: '人工价差'},
+    {type: 'materialDiff', name: '材料价差'},
+    {type: 'machineDiff', name: '机械价差'},
+    {type: 'adjustLabour', name: '调整人工费'},
+    {type: 'adjustMachineLabour', name: '调整机上人工费'},
+    {type: 'estimate', name: '暂估费'},
+    {type: 'common', name: '工程造价'}
+];

+ 21 - 5
web/building_saas/main/js/models/project.js

@@ -28,6 +28,7 @@ var PROJECT = {
                     me.eachItem(item)
                 }
             });
+
         };
         tools.doAfterLoad = function(result, callback){
             var counter;
@@ -269,9 +270,11 @@ var PROJECT = {
                         } else {
                             alert('error: ' + result.message);
                         }
+                        $.bootstrapLoading.end();
                     },
                     error: function(jqXHR, textStatus, errorThrown){
                         alert('error ' + textStatus + " " + errorThrown);
+                        $.bootstrapLoading.end();
                     }
                 });
                 tools.updateData = [];
@@ -304,17 +307,30 @@ var PROJECT = {
             }
             this.endUpdate();
         };
-
         project.prototype.registerModule = function(moduleName, obj){
             if (!tools.modules.hasOwnProperty(moduleName)){
                 tools.modules[moduleName] = obj;
             }
         };
+        project.prototype.markUpdateProject = function (data,type) {
+            CommonAjax.post("/project/markUpdateProject",{updateInfo:data,type:type});
+        };
 
-/*        project.prototype.setBillsCalcMode = function (calcMode) {
-            this.property.billsCalcMode = calcMode;
-            this.initCalcFields();
-        };*/
+        project.prototype.projectMarkChecking = function () {
+            let  changeMark = projectInfoObj.projectInfo.changeMark;
+            if(changeMark&&changeMark!=''){
+                $.bootstrapLoading.start();
+                this.Bills.getEngineeringCostNode(projectObj.mainController).changed = true;
+                this.calcProgram.calcAllNodesAndSave();
+                CommonAjax.post("/project/removeProjectMark",{projectID:this.ID()},function (data) {
+                    delete projectInfoObj.projectInfo.changeMark;
+                });
+            }
+        };
+        /*        project.prototype.setBillsCalcMode = function (calcMode) {
+                    this.property.billsCalcMode = calcMode;
+                    this.initCalcFields();
+                };*/
 
         /*project.prototype.initCalcFields = function () {
             // let settingConst = this.projSetting.settingConst;

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

@@ -140,11 +140,15 @@ ProjectGLJ.prototype.loadCacheData = function (resort) {
         return;
     }
     jsonData = data.gljList !== undefined && data.gljList.length > 0 ? data.gljList : [];
+    console.log("filter start");
     jsonData = filterProjectGLJ(jsonData);
+    console.log("filter end");
     jsonData = sortProjectGLJ(jsonData);
+    console.log("sort end");
     if(projectGLJSheet&&projectGLJSpread){
-        projectGLJSheet.setData(jsonData);
-        projectGLJSpread.specialColumn(jsonData);
+        setTimeout(spreadInit, 1);
+         /*projectGLJSheet.setData(jsonData);
+         projectGLJSpread.specialColumn(jsonData);*/
     }
 };
 
@@ -233,7 +237,7 @@ ProjectGLJ.prototype.updatePrice = function (recode, updateField, newval,from) {
     let pgljID = from=="rg"?recode.projectGLJID:recode.id;//和定额工料机统一接口,项目工料机ID取值不一样
     let glj = _.find(projectGljs, {'id': pgljID});
     if (glj) {
-        let data = {id: glj.unit_price.id, field: updateField, newval: newval};
+        let data = {id: glj.unit_price.id, field: updateField, newval: newval,project_id:glj.project_id};
         let callback = function (data) {
             if (updateField == 'base_price') {
                 glj.unit_price.base_price = newval;
@@ -250,6 +254,8 @@ ProjectGLJ.prototype.updatePrice = function (recode, updateField, newval,from) {
             gljs.push(glj);
             let nodes = me.getImpactRationNodes(gljs);//取到因为改变工料机价格而受影响的定额
             projectObj.project.calcProgram.calcRationsAndSave(nodes);//触发计算程序
+            socket.emit('unitFileChangeNotify', JSON.stringify(data));
+            projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),'unitFileID':socketObject.getUnitFileRoomID()},"unitFile");
             $.bootstrapLoading.end();
         }
         $.bootstrapLoading.start();
@@ -366,7 +372,7 @@ ProjectGLJ.prototype.setAdjustPrice = function (glj) {
 ProjectGLJ.prototype.getAdjustPrice = function (glj) {
     GLJTypeConst = this.datas.constData.GLJTypeConst !== undefined ? JSON.parse(this.datas.constData.GLJTypeConst) : GLJTypeConst;
     let decimal = getDecimal("glj.unitPrice");
-    let quantity_decimal = getDecimal("glj.quantity")
+    let quantity_decimal = getDecimal("glj.quantity");
     if (glj.unit_price.type == GLJTypeConst.LABOUR || glj.unit_price.type == GLJTypeConst.MACHINE_LABOUR) {//人工、机上人工,调整价根据定额价*调整系数计算得出。
         let labour = projectObj.project.calcProgram.compiledLabourCoes[glj.adjCoe];
         //let labour=1;
@@ -390,12 +396,59 @@ ProjectGLJ.prototype.getAdjustPrice = function (glj) {
     } else {//对于其他普通材料等,无调整系数,调整价=定额价。
         return glj.unit_price.base_price
     }
+};
+
+ProjectGLJ.prototype.getBasePrice = function(glj){
+    let price_decimal = getDecimal("glj.unitPrice");
+    let quantity_decimal = getDecimal("glj.quantity");
+    if (notEditType.indexOf(glj.unit_price.type)>0&&glj.ratio_data.length>0) {//对于混凝土、配合比、砂浆、机械台班等有组成物的材料,价格需根据组成物计算得出。
+        let p =0;
+        for(let ratio of glj.ratio_data){
+            let tem =  _.find( projectObj.project.projectGLJ.datas.gljList,{
+                'code': ratio.code,
+                'name': ratio.name,
+                'specs':ratio.specs,
+                'type': ratio.type,
+                'unit': ratio.unit
+            });
+            if(tem){
+                p+=scMathUtil.roundForObj(tem.unit_price.base_price*scMathUtil.roundForObj(ratio.consumption,quantity_decimal),price_decimal);
+            }
+        }
+        return scMathUtil.roundForObj(p,price_decimal);
+    }else {
+        return scMathUtil.roundForObj(glj.unit_price.base_price,price_decimal);
+    }
+};
+
+ProjectGLJ.prototype.getMarketPrice = function (glj) {
+    let price_decimal = getDecimal("glj.unitPrice");
+    let quantity_decimal = getDecimal("glj.quantity");
+    if (notEditType.indexOf(glj.unit_price.type)>0&&glj.ratio_data.length>0) {//对于混凝土、配合比、砂浆、机械台班等有组成物的材料,价格需根据组成物计算得出。
+        let p =0;
+        for(let ratio of glj.ratio_data){
+            let tem =  _.find( projectObj.project.projectGLJ.datas.gljList,{
+                'code': ratio.code,
+                'name': ratio.name,
+                'specs':ratio.specs,
+                'type': ratio.type,
+                'unit': ratio.unit
+            });
+            if(tem){
+                p+=scMathUtil.roundForObj(tem.unit_price.market_price*scMathUtil.roundForObj(ratio.consumption,quantity_decimal),price_decimal);
+            }
+        }
+        return scMathUtil.roundForObj(p,price_decimal);
+    }else {
+        return scMathUtil.roundForObj(glj.unit_price.market_price,price_decimal);
+    }
 }
 
+
 ProjectGLJ.prototype.getShortNameByID = function (ID) {
     let gljTypeMap = this.datas.constData.gljTypeMap;
     return gljTypeMap["typeId" + ID].shortName;
-}
+};
 
 ProjectGLJ.prototype.calcQuantity  = function (){
     let project_gljs = this.datas.gljList;

+ 24 - 9
web/building_saas/main/js/models/quantity_detail.js

@@ -164,7 +164,7 @@ var quantity_detail = {
                 let newNode = nodes[0];
                 if(newNode.sourceType === project.Bills.getSourceType()){
                     console.log(newNode.data.quantity);
-                    this.updateBillQuantity(newNode.data.quantity,newNode);
+                    this.updateBillQuantity(newNode.data.quantity,newNode,newNode.data.quantityEXP);
                 }else {//更新定额所使用的值要用还没转换前的
                     this.updateRationQuantity(node.data.r_quantity,newNode,newNode.data.quantityEXP);//to do 加上工程量表达式和含量更新
                 }
@@ -511,13 +511,24 @@ var quantity_detail = {
         quantity_detail.prototype.autoTransformQuantity = function(value,node){//根据单位转换定额工程量
             let data = node.data;
             let option = optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS,'rationQuanACToRationUnit');
-            if(option==true&&node.sourceType === project.Ration.getSourceType()&&data.unit) {//还需加入判读是否转换
+            if(node.data.quantityEXP=='GCLMXHJ'||(option==true&&node.sourceType === project.Ration.getSourceType()&&data.unit)) {//还需加入判读是否转换,如果是来自工程量明细的话,默认都进行转换
                 let times = parseInt(data.unit);
                 if (isNaN(times)) {
                     times = 1
                 }
                 value = value / times;
             }
+            let EXPString=node.data.quantityEXP+"";
+            if(option==false&&node.sourceType === project.Ration.getSourceType()&&EXPString!='GCLMXHJ'&&EXPString.indexOf("QDL")==-1&&data.unit){//勾选不根据单位转换工程量,且定额是手输的,
+                let times = parseInt(data.unit);
+                if(!isNaN(times)){///如果定额单位可以做转换
+                    if(isNum(EXPString)){//如果表达式中只是数字
+                        node.data.quantityEXP = EXPString+" * "+times;
+                    }else {//如果表达式是一个计算式,则要加一个括号
+                        node.data.quantityEXP = "("+EXPString+") * "+times;
+                    }
+                }
+            }
             return value;
         };
         quantity_detail.prototype.reverseQuantity = function (value,node) {//根据单位反向运算出工程量
@@ -531,10 +542,10 @@ var quantity_detail = {
             }
             return value
         };
-        quantity_detail.prototype.editMainTreeNodeQuantity=function (value,node,fieldName) {
+        quantity_detail.prototype.editMainTreeNodeQuantity=function (value,node,fieldName,editingText) {
             var me = this;
             if(isNaN(value)){
-                alert("当前输入的数据类型不正确,请重新输入");
+                alert("当前输入的数据类型不正确,请重新输入");
                 projectObj.mainController.refreshTreeNode([node]);
             }else {
                 value=value?value:0;
@@ -542,10 +553,11 @@ var quantity_detail = {
                     if(project.quantity_detail.quantityEditChecking(value,node,fieldName)){
                         node.data.isFromDetail=0;
                         project.quantity_detail.cleanQuantityDetail(node,true);
+                        $.bootstrapLoading.start();
                         if(node.sourceType === project.Bills.getSourceType()){
-                            me.updateBillQuantity(value,node);
+                            me.updateBillQuantity(value,node,null,editingText);
                         }else {
-                            me.updateRationQuantity(value,node);
+                            me.updateRationQuantity(value,node,null,editingText);
                         }
                     }else {
                         projectObj.mainController.refreshTreeNode([node]);
@@ -553,9 +565,11 @@ var quantity_detail = {
                 },100);
             }
         };
-        quantity_detail.prototype.updateBillQuantity=function (value,node) {
+        quantity_detail.prototype.updateBillQuantity=function (value,node,quantityEXP,editingText) {
+            node.data.quantityEXP = quantityEXP?quantityEXP:editingText;
             value = scMathUtil.roundForObj(value,getDecimal("quantity",node));
             node.data.quantity = value+"";
+            console.log(value);
             let needUpdateChildren = [];//需更新的子定额
             let gljNodes=[];//当定额工程量改变时需刷新的子工料机
             if(node.children.length>0){//如果有子项则
@@ -584,6 +598,7 @@ var quantity_detail = {
                 }
             }
             if(needUpdateChildren.length>0){
+                node.changed = true;//本身发生了改变,需要存储。
                 project.calcProgram.calcRationsAndSave(needUpdateChildren);
             }else {
                 node.changed = true;
@@ -593,8 +608,8 @@ var quantity_detail = {
                 projectObj.mainController.refreshTreeNode(gljNodes);
             }
         };
-        quantity_detail.prototype.updateRationQuantity=function(value,node,quantityEXP){
-            node.data.quantityEXP = quantityEXP?quantityEXP:value;
+        quantity_detail.prototype.updateRationQuantity=function(value,node,quantityEXP,editingText){
+            node.data.quantityEXP = quantityEXP?quantityEXP:editingText;
             value = scMathUtil.roundForObj(value,getDecimal("ration.quantity"));
             if(node.parent.data.quantity&&node.parent.data.quantity!=0&&node.parent.data.quantity!=""){
                 var billQuantity = scMathUtil.roundForObj(node.parent.data.quantity,getDecimal("quantity",node.parent));

+ 14 - 7
web/building_saas/main/js/models/ration.js

@@ -124,12 +124,11 @@ var Ration = {
         };
 
         // CSL, 2017-11-13 取任何清单(父清单、叶子清单)下的所有定额
-        ration.prototype.getRationsByNode = function (billNode) {
-            let rations = [];
-            let sBills = 'bills';
-            if (billNode.sourceType != sBills) return rations;
+        ration.prototype.getRationNodes = function (billNode) {
+            if (billNode.sourceType != ModuleNames.bills) return [];
+
+            let rations = [], IDs = [];
 
-            let IDs = [];
             function getSubBillsIDs(node) {
                 if (!node) return;
                 if (node.sourceType != sBills) return;
@@ -151,10 +150,17 @@ var Ration = {
                 });
                 rations.push(...subRations);
             };
+
             rations.sort(function (x, y) {
                 return x.serialNo - y.serialNo;
             });
-            return rations;
+
+            let rationNodes = [];
+            for (let ration of rations){
+                  rationNodes.push(projectObj.project.mainTree.nodes['id_' + ration.ID]);
+            };
+
+            return rationNodes;
         };
 
         ration.prototype.getInsertRationData = function (billsID, preRation, rationType) {
@@ -164,7 +170,7 @@ var Ration = {
                 var preIndex = br.indexOf(preRation), i;
                 updateData.push({updateType: 'ut_create', updateData: this.getTempRationData(this.getNewRationID(), billsID, preIndex < br.length - 1 ? br[preIndex + 1].serialNo : br[preIndex].serialNo + 1, rationType)});
                 for (i = preIndex + 1; i < br.length; i++) {
-                    updateData.push({updateType: 'ut_update', updateData: this.getTempRationData(br[i].ID, billsID, i < br.length - 1 ? br[i+1].serialNo : br[i].serialNo + 1, rationType)});
+                    updateData.push({updateType: 'ut_update', updateData: this.getTempRationData(br[i].ID, billsID, i < br.length - 1 ? br[i+1].serialNo : br[i].serialNo + 1, br[i].type)});
                 }
             } else {
                 updateData.push({updateType: 'ut_create', updateData: this.getTempRationData(this.getNewRationID(), billsID, br.length > 0 ? br[br.length - 1].serialNo + 1 : 1, rationType)});
@@ -349,6 +355,7 @@ var Ration = {
             if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan')) {
                 let billsNode = this.project.Bills.tree.findNode(ration[this.project.masterField.ration]);
                 let billsQuantity = billsNode.data.quantity ? billsNode.data.quantity : 0;
+                billsQuantity=scMathUtil.roundForObj(billsQuantity,quantity_decimal);
                 ration.contain = 1;
                 ration.quantityEXP="QDL";
                 if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToRationUnit')) {

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

@@ -86,7 +86,7 @@ var ration_coe = {
                     newCoe.isAdjust=0;
                     newCoe.coes = this.getCustomerCoeData();
                 }else {
-                    newCoe.coeID= data.rationCoeList[i];
+                    newCoe.coeID= data.rationCoeList[i].ID;
                 }
                 criteria.ration_coe_list.push(newCoe);
             }

+ 10 - 10
web/building_saas/main/js/models/ration_glj.js

@@ -118,8 +118,11 @@ var ration_glj = {
                 gljOprObj.showRationGLJSheetData(true);
                 //add to mainTree;
                 me.addToMainTree(neRecodes);
-                let node = project.mainTree.selected;
-                project.calcProgram.calcAndSave(node);
+                let rationID = neRecodes[0].rationID;
+                let node = project.mainTree.nodes['id_' + rationID];
+                if(isDef(node)){
+                    project.calcProgram.calcAndSave(node);
+                }
                 if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
                     calcProgramObj.showData(node, false);
                 }
@@ -143,7 +146,7 @@ var ration_glj = {
                             }
                         }
                         nextNodeID = nextNodeID ? nextNodeID : parentNode.tree.rootID();
-                        let newNode = projectObj.project.mainTree.insert(parentNode.getID(), nextNodeID);
+                        let newNode = projectObj.project.mainTree.insert(parentNode.getID(), nextNodeID,data.ID);
                         newNode.source = data;
                         newNode.sourceType = this.getSourceType();
                         newNode.data = data;
@@ -492,7 +495,6 @@ var ration_glj = {
                 rationCount: project.Ration.maxRationID()
             }
             selectedSerialNo == null ? "" : postData.selectedSerialNo = selectedSerialNo;
-            $.bootstrapLoading.start();
             CommonAjax.post("/ration/insertGLJAsRation", postData, function (data) {
                 // 更新兄弟节点的序列号
                 if (selectedSerialNo != null) {
@@ -503,7 +505,7 @@ var ration_glj = {
                         }
                     }
                 }
-                let newNode=null;
+              /*  let newNode=null;
                 for (let r_glj of data) {
                     r_glj.marketUnitFee = r_glj.marketPrice;
                     r_glj.quantity = r_glj.quantity + "";
@@ -513,12 +515,9 @@ var ration_glj = {
                     newNode.sourceType = project.Ration.getSourceType();
                     newNode.data = r_glj;
                     ProjectController.syncDisplayNewNode(projectObj.mainController, newNode);
-                }
-                let parentNode = project.mainTree.nodes[project.mainTree.prefix + parentNodeID];
-                project.calcProgram.calcLeafAndSave(parentNode);//计算父级清单的所有子节点
+                }*/
                 //this.nodes[this.prefix + parentID];
-                callback(newNode);
-                $.bootstrapLoading.end();
+                callback(parentNodeID,nextNodeID,data);
             }, function () {
                 $.bootstrapLoading.end();
             });
@@ -677,6 +676,7 @@ var ration_glj = {
                     if (typeString.indexOf("2") != -1) {//只有材料类型才显示是否暂估
                         ration.isEstimate = glj.is_evaluate;
                     }
+                    ration = gljOprObj.setGLJPrice(ration,glj);
                     ration.basePrice = glj.unit_price.base_price;
                     ration.marketUnitFee = glj.unit_price.market_price;
                     ration.isAdd = glj.unit_price.is_add;

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

@@ -79,7 +79,10 @@ let calcBaseView = {
         let cols = this.setting.header;
         let fuc = function () {
             sheet.setRowCount(datas.length);
-            sheet.setFormatter(-1, 1, '@');
+            //sheet.setFormatter(-1, 1, '@');
+            let style = new GC.Spread.Sheets.Style();
+            style.formatter = MainTreeCol.getNumberFormatter(decimalObj.bills.totalPrice, true);
+            sheet.setStyle(-1, 1, style);
             for(let col = 0, cLen = cols.length; col < cLen; col++){
                 sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
                 sheet.getRange(-1, col, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
@@ -212,11 +215,11 @@ let calcBaseView = {
         }
         CalcBaseCellType.prototype = new ns.CellTypes.Text();
         CalcBaseCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
-            if(value!=null){
+          //  if(value!=null){
                // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
                // ctx.fillText(value,x+w-3,y+h-3);
                 GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
-            }
+           // }
             if(calcBaseView.editingCell){
                 if(calcBaseView.editingCell.row==options.row&&calcBaseView.editingCell.col==options.col){
                     var image = document.getElementById('f_btn'),imageMagin = 3;

+ 31 - 5
web/building_saas/main/js/views/calc_program_manage.js

@@ -52,8 +52,10 @@ let calcProgramManage = {
         };
         me.mainSpread = sheetCommonObj.buildSheet($('#mainSpread')[0], me.mainSetting, me.datas.length);
         me.detailSpread = sheetCommonObj.buildSheet($('#detailSpread')[0], me.detailSetting, me.datas[0].calcItems.length);
-        var fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
-        fieldName.items(projectObj.project.calcProgram.compiledFeeTypeNames);
+        let arr = projectObj.project.calcProgram.compiledFeeTypeNames.slice();
+        arr.splice(arr.findIndex(function (e){return e == '暂估费'}), 1);
+        let fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
+        fieldName.items(arr);
         me.detailSpread.getSheet(0).getRange(-1, 4, -1, 1).cellType(fieldName);
 
         me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
@@ -79,10 +81,32 @@ let calcProgramManage = {
         me.detailSpread.resumePaint();
     },
     onEditEnded: function(sender, args) {
-        var me = calcProgramManage;
-        if(me.detailSetting.header[args.col].dataCode=='feeRate'){
-            var editInfo= me.getSelectionInfo();
+        $.bootstrapLoading.start();
+
+        let me = calcProgramManage;
+        let editInfo= me.getSelectionInfo();
+        if(me.detailSetting.header[args.col].dataCode == 'feeRate'){
             projectObj.project.FeeRate.updateFeeRateFromCalc(args.editingText,editInfo);
+        }else {
+            if(me.detailSetting.header[args.col].dataCode == 'displayFieldName'){
+                if (editInfo.calcItem.displayFieldName == args.editingText) {
+                    $.bootstrapLoading.end();
+                    return;
+                }
+                editInfo.calcItem.fieldName = projectObj.project.calcProgram.compiledFeeTypeMaps[args.editingText];
+                editInfo.calcItem.displayFieldName = args.editingText;    // 这句不入库,仅用于切换后再切换回来时界面正确显示
+            };
+
+            let data = {
+                'projectID': projectObj.project.ID(),
+                'templatesID': editInfo.template.ID,
+                'calcItem': editInfo.calcItem
+            };
+            me.saveCalcItem(data, function (rst) {
+                if (rst){
+                    projectObj.project.calcProgram.calcAllNodesAndSave();
+                }
+            });
         }
     },
     saveCalcItem: function (data,callback) {//data
@@ -96,11 +120,13 @@ let calcProgramManage = {
                 if(!result.error){
                     if(callback){
                         callback(result);
+                        return;
                     }
                 }
                 else{
                     alert('失败:' + result.message);
                 }
+                $.bootstrapLoading.end();
             }
         })
     },

+ 10 - 0
web/building_saas/main/js/views/calc_program_view.js

@@ -50,6 +50,16 @@ let calcProgramObj = {
         sheetCommonObj.showData(me.sheet, me.setting, me.datas);
     },
 
+    refreshCurNodeCalcItems: function (treeNode) {
+        var me = this;
+        me.treeNode = treeNode;
+        projectObj.project.calcProgram.innerCalc(treeNode, []);
+        delete treeNode.changed;
+        me.datas = treeNode.data.calcTemplate ? treeNode.data.calcTemplate.calcItems : [];
+        sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
+        sheetCommonObj.showData(me.sheet, me.setting, me.datas);
+    },
+
     clearData: function (){
         var me = this;
         me.treeNode = null;

+ 21 - 0
web/building_saas/main/js/views/character_content_view.js

@@ -293,6 +293,7 @@ let characterOprObj = {
         sheet.bind(EVENTS.EditStarting, me.onEditStart);
         sheet.bind(EVENTS.ClipboardPasting, me.onClipboardPasting);
         sheet.bind(EVENTS.ClipboardPasted, me.onClipboardPasted);
+        workBook.bind(EVENTS.RangeChanged, me.onRangeChanged);
     },
     //将从清单库中添加的清单,把标准清单的项目特征转化成清单的项目特征
     buildItemCharactet: function (items) {//从清单库过来的默认不输出
@@ -562,6 +563,24 @@ let characterOprObj = {
         }
         me.save();
     },
+    onRangeChanged: function (sender, args) {
+        let me = characterOprObj;
+        let rangeCell = isDef(args.changedCells[0]) ? args.changedCells[0] : null;
+        if(!rangeCell){
+            return;
+        }
+        let rangeData = isDef(me.currentCache[rangeCell.row]) ? me.currentCache[rangeCell.row] : null;
+        if(!rangeData){
+            return;
+        }
+        if(rangeCell.col === 1){//特征值
+            rangeData.isChecked = false;
+            for(let value of rangeData.eigenvalue){
+                value.isSelected = false;
+            }
+        }
+        me.save();
+    },
     //复选框控制输出
     onButtonClicked: function (sender, args) {
         let me = characterOprObj, characterTxt;
@@ -833,6 +852,8 @@ let pageCCOprObj = {
             saveObj.push({field: index, value: updateData[index]});
         }
         saveObj.push({field: 'addRule', value: setting});
+        saveObj.push({field: 'jobContent', value: node.data.jobContent});
+        saveObj.push({field: 'itemCharacter', value: node.data.itemCharacter});
         // 更新到数据库
         pageCCOprObj.updateBill(findSet, saveObj, function(response) {
             self.refreshView(node, updateData);

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

@@ -251,10 +251,10 @@ var feeRateObject={
         }
         FeeRateEditCellType.prototype = new ns.CellTypes.Text();
         FeeRateEditCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
-            if(value!=null){
+           // if(value!=null){
                // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
-                ctx.fillText(value,x+w-3,y+h-3);
-            }
+             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
+           // }
             if(feeRateObject.editingCell){
                 if(feeRateObject.editingCell.row==options.row&&feeRateObject.editingCell.col==options.col){
                     var image = document.getElementById('f_btn'),imageMagin = 3;
@@ -648,6 +648,7 @@ var feeRateObject={
     submitFeeRateFromBill:function () {
        var rate = feeRateObject.feeRateSelection;
        var selected = projectObj.project.mainTree.selected;
+        $.bootstrapLoading.start();
         projectObj.project.FeeRate.submitFeeRateFromBill(rate,selected.data,function (data) {
             selected.data.feeRateID=rate.ID.toString();
             selected.data.feeRate=scMathUtil.roundToString(rate.rate,getDecimal("feeRate"));
@@ -663,9 +664,11 @@ var feeRateObject={
         calInfo.calcItem.feeRateID=rate.ID;
         calInfo.calcItem.feeRate=null;
         var data={'projectID': projectObj.project.ID(),'templatesID': calInfo.template.ID,'calcItem': calInfo.calcItem};
+        $.bootstrapLoading.start();
         calcProgramManage.saveCalcItem(data,function (result) {
             calInfo.calcItem.feeRate=rate.rate;
             projectObj.project.calcProgram.compileAllTemps();
+            projectObj.project.calcProgram.calcAllNodesAndSave();
             calcProgramManage.refreshDetailSheet();
             $("#fee_rate_tree").modal('hide');
         });

+ 44 - 16
web/building_saas/main/js/views/glj_view.js

@@ -171,7 +171,7 @@ var gljOprObj = {
             onClick: function (event, treeId, treeNode) {
                 if (treeId == 'gljTree') {
                     let me = gljOprObj, gljTypeId = treeNode.ID;
-                    if (me.gljCurTypeId !== treeNode.ID) {
+                    if (treeNode.ID) {
                         me.gljCurTypeId = treeNode.ID;
                         me.filterLibGLJSheetData();
                         me.showLibGLJSheetData();
@@ -741,6 +741,7 @@ var gljOprObj = {
         this.sheetData = gljList;
         this.sheet.setRowCount(0);
         this.sheetData = sortRationGLJ(this.sheetData);
+        this.sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType([]));
         sheetCommonObj.showData(this.sheet, this.setting, this.sheetData);
 
         this.sheet.getRange(-1, 0, -1, this.setting.header.length).locked(true);//锁住定额工料机的所有列
@@ -758,9 +759,15 @@ var gljOprObj = {
         var ration_glj = projectObj.project.ration_glj;
         node = node ? node : projectObj.project.mainTree.selected;
         if (node.sourceType == ModuleNames.ration) {
-            let ration = node.data;
-            gljList = this.filterGljByRation(ration, ration_glj.datas);
-            this.showInSheet(gljList);
+            if(node.data.type==rationType.gljRation){
+                this.showMixRatio(node);
+            }else {
+                let ration = node.data;
+                gljList = this.filterGljByRation(ration, ration_glj.datas);
+                this.showInSheet(gljList);
+            }
+        }else if(node.sourceType == ModuleNames.ration_glj){
+            this.showMixRatio(node);
         }
     },
     showRationGLJSheetData: function (init) {
@@ -782,13 +789,14 @@ var gljOprObj = {
         this.sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType(this.sheetData));
         for (var i = 0; i < this.sheetData.length; i++) {
             if (this.sheetData[i].hasOwnProperty('subList')) {
-                var collapsed = false;
+               /* var collapsed = false;
                 if (init) {
                     this.sheetData[i].collapsed = true;
                     collapsed = true;
                 } else {
                     collapsed = this.sheetData[i].collapsed == undefined ? true : this.sheetData[i].collapsed;
-                }
+                }*/
+                var collapsed = this.sheetData[i].collapsed == undefined ? true : this.sheetData[i].collapsed;
                 if (collapsed == true) {
                     this.sheet.getRange(i + 1, -1, this.sheetData[i].subList.length, -1).visible(false);
                 }
@@ -880,15 +888,16 @@ var gljOprObj = {
         return ration_gljs;
     },
     setGLJPrice:function (data,glj) {
-        glj = glj?glj:_.find(projectObj.project.projectGLJ.datas.projectGljs, {'id': ration_gljs[i].projectGLJID});
+        let proGLJ =  projectObj.project.projectGLJ;
+        glj = glj?glj:_.find(proGLJ.datas.gljList, {'id': data.projectGLJID});
         if(this.calcPriceDiff(glj)==true) {//计取价差
-            data.basePrice = glj.unit_price.base_price;
-            data.marketPrice = glj.unit_price.market_price;
-            data.adjustPrice = projectObj.project.projectGLJ.getAdjustPrice(glj);
+            data.basePrice = proGLJ.getBasePrice(glj);
+            data.marketPrice = proGLJ.getMarketPrice(glj);
+            data.adjustPrice = proGLJ.getAdjustPrice(glj);
         }else {//不计价差
-            data.basePrice = glj.unit_price.market_price;
-            data.marketPrice = glj.unit_price.market_price;
-            data.adjustPrice = glj.unit_price.market_price;
+            data.basePrice = proGLJ.getMarketPrice(glj);
+            data.marketPrice = proGLJ.getMarketPrice(glj);
+            data.adjustPrice = proGLJ.getMarketPrice(glj);
         }
         return data;
 
@@ -922,6 +931,9 @@ var gljOprObj = {
         let obj ={};
         for(let i = 0;i<valueArray.length;i++){
             if(valueArray[i]!='null'){
+                if(gljKeyArray[i]=='type'){
+                    valueArray[i] = parseInt(valueArray[i]);
+                }
                 obj[gljKeyArray[i]]=valueArray[i];
             }
         }
@@ -1278,13 +1290,29 @@ var gljOprObj = {
             return;
         }
         $("#glj_tree_div").modal('hide');
-        project.ration_glj.insertGLJAsRation(me.GLJSelection, selected, function (node) {
+        $.bootstrapLoading.start();
+        project.ration_glj.insertGLJAsRation(me.GLJSelection, selected, function (parentNodeID,nextNodeID,data) {
             project.projectGLJ.loadData(function () {
-                if(me.hasComposition(node.data,true)){
-                    me.showMixRatio(node);
+                  let newNode=null;
+                 for (let r_glj of data) {
+                     r_glj = me.setGLJPrice(r_glj);//设置工料机价格
+                     r_glj.marketUnitFee = r_glj.marketPrice;
+                     r_glj.quantity = r_glj.quantity + "";
+                     project.Ration.datas.push(r_glj);
+                     newNode = project.mainTree.insert(parentNodeID, nextNodeID, r_glj.ID);
+                     newNode.source = r_glj;
+                     newNode.sourceType = project.Ration.getSourceType();
+                     newNode.data = r_glj;
+                     ProjectController.syncDisplayNewNode(projectObj.mainController, newNode);
+                 }
+                project.calcProgram.calcLeafAndSave(newNode.parent);//计算父级清单的所有子节点
+                projectObj.mainController.refreshTreeNode([newNode]);
+                if(me.hasComposition(newNode.data,true)){
+                    me.showMixRatio(newNode);
                 }else {
                     me.showRationGLJSheetData();
                 }
+                $.bootstrapLoading.end();
             });
 
         })

+ 5 - 0
web/building_saas/main/js/views/glj_view_contextMenu.js

@@ -197,7 +197,10 @@ var gljContextMenu = {
 
 function getGLJData(actionType) {
     $('#actionType').val(actionType);
+    $.bootstrapLoading.start();
+    console.log(+new Date());
     projectObj.project.ration_glj.getGLJData(function (result) {
+        console.log(+new Date());
         zTreeHelper.createTree(result.datas.treeData, gljOprObj.gljTreeSetting, "gljTree", gljOprObj);
         gljOprObj.stdGLJ=result.datas.stdGLJ;
         gljOprObj.complementaryGLJs=result.datas.complementaryGLJs;
@@ -205,6 +208,8 @@ function getGLJData(actionType) {
         gljOprObj.distTypeTree=gljOprObj.getComboData(result.datas.distTypeTree);
         $('#modalCon').width($(window).width()*0.5);
         $("input[name='glj']").get(0).checked=true;
+        $.bootstrapLoading.end();
+        console.log(+new Date());
         $("#glj_tree_div").modal({show:true});
     })
 }

+ 42 - 8
web/building_saas/main/js/views/main_tree_col.js

@@ -25,7 +25,7 @@ let MainTreeCol = {
           if(node.sourceType === projectObj.project.ration_glj.getSourceType()){
               return gljOprObj.getTotalQuantity(node.data);
           }else {
-              return node.data["quantity"];
+              return calcTools.uiNodeQty(node)?calcTools.uiNodeQty(node):null;
           }
         },
         // CSL, 2017-11-28
@@ -46,11 +46,18 @@ let MainTreeCol = {
             else {
                 return isDef(node.data.code) ? node.data.code : '';
             }
+        },
+        marketPrice:function (node) {
+            if((node.sourceType === projectObj.project.Ration.getSourceType()&&node.data.type!=rationType.ration)||node.sourceType==projectObj.project.ration_glj.getSourceType()){
+                return assistCalcer.uiGLJPrice(node.data.marketUnitFee);
+            }
         }
     },
     readOnly: {
         // Vincent, 2018-01-09
         subType: function (node) {
+            if (calcTools.isVolumePrice(node)) return false;
+
             if(MainTreeCol.readOnly.bills(node)){
                 return true;
             }
@@ -67,7 +74,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (treeNodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (calcTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) return false
             else return true;
         },
@@ -75,7 +82,7 @@ let MainTreeCol = {
             return node.data.subType != 201 && node.data.subType != 4 && node.data.subType != 5
         },
         commonUnitFee: function (node) {
-            return !treeNodeTools.isNullBill(node);
+            return !calcTools.isNullBill(node);
         },
         //根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
@@ -109,7 +116,10 @@ let MainTreeCol = {
             return node.sourceType === projectObj.project.Bills.getSourceType();
         },
         ration: function (node) {
-            return treeNodeTools.isRation(node);
+            return calcTools.isRationItem(node);
+        },
+        isSubcontract: function (node) {
+            return !calcTools.isRationCategory(node);
         },
         glj: function (node) {
             return node.sourceType == projectObj.project.ration_glj.getSourceType();
@@ -149,13 +159,32 @@ let MainTreeCol = {
             return MainTreeCol.readOnly.non_bills(node) || MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.leafBillsWithDetail(node)
         },
         forQuantity: function (node) {
-            return MainTreeCol.readOnly.glj(node) || MainTreeCol.readOnly.billsParent(node)
+            if(node.sourceType === projectObj.project.Bills.getSourceType()){
+                if(node.data.type==billType.DXFY||node.data.type==billType.FB||(node.data.type==billType.BILL&&MainTreeCol.readOnly.billsParent(node))){//大项费用、分部、清单父项行,工程量只读。
+                    return true;
+                }
+            }else if(MainTreeCol.readOnly.glj(node)){
+                return true;
+            }
+            return false;
         },
         forMarketPrice: function (node) {
-            return MainTreeCol.readOnly.bills(node) || (node.sourceType === ModuleNames.ration && (node.data.type == rationType.ration||node.data.type== rationType.volumePrice)) || gljOprObj.marketPriceReadOnly(node);
+            return MainTreeCol.readOnly.bills(node) ||
+                (node.sourceType === ModuleNames.ration && node.data.type == rationType.ration) ||
+                gljOprObj.marketPriceReadOnly(node);
         },
         forContain:function (node) {
             return MainTreeCol.readOnly.non_ration(node)&&!MainTreeCol.readOnly.glj(node);
+        },
+        forCode:function (node) {
+            return MainTreeCol.readOnly.glj(node)|| (node.sourceType === projectObj.project.Ration.getSourceType()&&node.data.type===rationType.gljRation);
+        },
+        forUnit:function (node) {
+            if(MainTreeCol.readOnly.bills(node)&&(node.data.type==billType.DXFY||node.data.type==billType.FB)){//在大项费用、分部行,计量单位只读。
+                return true;
+            }else {
+               return calcTools.isRationItem(node);
+            }
         }
     },
     cellType: {
@@ -163,7 +192,7 @@ let MainTreeCol = {
             //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
             let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
             dynamicCombo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
-                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
+                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']).editable(true);
             return dynamicCombo;
         },
 
@@ -183,7 +212,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (treeNodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (calcTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) {
                 // var names = new GC.Spread.Sheets.CellTypes.ComboBox();
                 var names = sheetCommonObj.getDynamicCombo();
@@ -214,6 +243,11 @@ let MainTreeCol = {
                 }
             }
         },
+
+        isSubcontract: function (node){
+            if (calcTools.isRationCategory(node))
+                return new GC.Spread.Sheets.CellTypes.CheckBox();
+        }
     },
     getEvent: function (eventName) {
         let names = eventName.split('.');

+ 61 - 1
web/building_saas/main/js/views/options_view.js

@@ -3,6 +3,66 @@
  */
 let optionsOprObj = {
     options: null,
+    optionsTypes: {GENERALOPTS: 'GENERALOPTS', COLOROPTS: 'COLOROPTS'},
+    rationQuanACToBillsQuan: $('#generalOpts1'),
+    rationQuanACToRationUnit: $('#generalOpts2'),
+    getOptions: function () {
+        let me = this;
+        CommonAjax.post('/options/getOptions', [], function (rstData) {
+            me.options = rstData;
+            let gOpts = me.options[me.optionsTypes.GENERALOPTS];
+            if(isDef(gOpts)){
+                for(let attr in gOpts){
+                    me[attr][0].checked = gOpts[attr];
+                }
+            }
+        });
+    },
+    saveOptions: function (type, opts) {
+        let optSettingType = 'options.' + type;
+        let postData = Object.create(null);
+        postData[optSettingType] = opts;
+        CommonAjax.post('/options/saveOptions', {optSetting: postData});
+    },
+    //更新optionsOprObj对象options数据
+    updateOptions: function (options, updateObj) {
+        if(isDef(options[updateObj.type])){
+            options[updateObj.type][updateObj.opt] = updateObj.value;
+        }
+    },
+    getOptsByType: function (options, type) {
+        return isDef(options[type]) ? options[type] : null;
+    },
+    getOption: function (type, optionName) {
+        if(!isDef(optionName)){
+            return isDef(this.options[type]) ? this.options[type] : null;
+        }
+        else {
+            return isDef(this.options[type][optionName])
+                ? this.options[type][optionName]
+                    : optionName === this.optionsTypes.GENERALOPTS
+                    ? true
+                : null;
+        }
+    }
+};
+
+optionsOprObj.getOptions();
+optionsOprObj.rationQuanACToBillsQuan.click(function () {
+    let value = this.checked;
+    optionsOprObj.updateOptions(optionsOprObj.options, {type: optionsOprObj.optionsTypes.GENERALOPTS, opt: 'rationQuanACToBillsQuan', value: value});
+    optionsOprObj.saveOptions(optionsOprObj.optionsTypes.GENERALOPTS, optionsOprObj.getOptsByType(optionsOprObj.options, optionsOprObj.optionsTypes.GENERALOPTS));
+});
+optionsOprObj.rationQuanACToRationUnit.click(function () {
+    let value = this.checked;
+    optionsOprObj.updateOptions(optionsOprObj.options, {type: optionsOprObj.optionsTypes.GENERALOPTS, opt: 'rationQuanACToRationUnit', value: value});
+    optionsOprObj.saveOptions(optionsOprObj.optionsTypes.GENERALOPTS, optionsOprObj.getOptsByType(optionsOprObj.options, optionsOprObj.optionsTypes.GENERALOPTS));
+});
+
+
+
+/*let optionsOprObj = {
+    options: null,
     optionsTypes: {GENERALOPTS: 'GENERALOPTS'},
     rationQuanACToBillsQuan: $('#generalOpts1'),
     rationQuanACToRationUnit: $('#generalOpts2'),
@@ -58,4 +118,4 @@ optionsOprObj.rationQuanACToRationUnit.click(function () {
     let value = this.checked;
     optionsOprObj.updateOptions(optionsOprObj.options, {type: optionsOprObj.optionsTypes.GENERALOPTS, opt: 'rationQuanACToRationUnit', value: value});
     optionsOprObj.saveOptions(optionsOprObj.optionsTypes.GENERALOPTS, optionsOprObj.getOptsByType(optionsOprObj.options, optionsOprObj.optionsTypes.GENERALOPTS));
-});
+});*/

+ 0 - 18
web/building_saas/main/js/views/project_property_labour_coe_view.js

@@ -150,24 +150,6 @@ let labourCoeView = {
         $("#std_labour_coe_files").val('');
         calcProgramManage.buildSheet();
     }
-
-/*  save(){
-        let me = this;
-        if (me.needUpdateDatas.length > 0){
-            let projectID = projectInfoObj.projectInfo.ID;
-            let libID = $("#std_labour_coe_files").children("option:selected").val();
-            let libName = $("#std_labour_coe_files").children("option:selected").text();
-            let data = {projectID: projectID, libID: libID, libName: libName, newItemArr: me.needUpdateDatas};
-            CommonAjax.post('/labourCoe/save', data, function (){
-                projectObj.project.labourCoe.refreshData(data);
-                me.needUpdateDatas.splice(0, me.needUpdateDatas.length);
-                projectObj.project.calcProgram.compileAllTemps();
-                projectObj.project.calcProgram.calcAllNodes(calcAllType.catRations);
-                $("#std_labour_coe_files").val('');
-                calcProgramManage.buildSheet();
-            });
-        }
-    }*/
 };
 
 $(document).ready(function(){

+ 0 - 3
web/building_saas/main/js/views/project_property_projFeature.js

@@ -158,9 +158,6 @@ let projFeatureView = {
         let me = projFeatureView;
         let items = sheetCommonObj.analyzePasteData(me.setting, args);
         let recRows = [];
-        console.log(args);
-        console.log(items);
-        console.log('enter');
         if(items.length === 0){
             return;
         }

+ 357 - 174
web/building_saas/main/js/views/project_view.js

@@ -31,6 +31,12 @@ var projectObj = {
                 pageCCOprObj.clearData();
             }
         }
+
+        // for test interface.  CSLAAAAA
+/*        node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
+        node.data.isSubcontract = true;
+        let bname = '分包人工工日';
+        alert(bname + ': ' + rationCalcBases[bname](node));*/
     },
     refreshBaseActn: function (tree) {
         let setButtonValid = function (valid, btn) {
@@ -41,66 +47,89 @@ var projectObj = {
             }
         };
         let selected = tree.selected, that = projectObj;
+
         let canUpLevel = function (node) {
-            if (selected && selected.depth() > 0 && selected.canUpLevel()) {
-                if (selected.sourceType === that.project.Bills.getSourceType()) {
-                    return (!selected.nextSibling) || (selected.children.length === 0) || (selected.source.children.length > 0);
-                } else {
+            if(!node){
+                return false;
+            }
+            if(node.depth()<=1){//焦点行是树结构的第一/二层节点,灰显。
+                return false;
+            }
+            if(node.sourceType !== that.project.Bills.getSourceType()){//焦点行是定额/量价/工料机,灰显。
+                return false;
+            }else {
+                if(node.data.type == billType.FX){//是分项,灰显。
                     return false;
                 }
-            } else {
-                return false;
+                if(node.data.type == billType.FB&&node.nextSibling&&node.children.length>0){//焦点行是分部有后兄弟,有子项.
+                     if(node.children[0].data.type==billType.FX){ //焦点行子项是分项
+                         return false;
+                     }
+                }
+                if(node.data.type == billType.BILL &&node.nextSibling){//焦点行是清单有后兄弟
+                    if(node.data.calcBase&&node.data.calcBase!=""){//有基数计算
+                        return false;
+                    }
+                    if(node.children.length>0&&node.children[0].sourceType !== that.project.Bills.getSourceType()){//有子项,并且子项不是清单
+                        return false;
+                    }
+                }
             }
+            return true;
         };
         let canDownLevel = function (node) {
-            if (selected && selected.depth() > 0 && selected.canDownLevel()) {
-                if (selected.sourceType === that.project.Bills.getSourceType()) {
-                    return (selected.preSibling.children.length === 0) || (selected.preSibling.source.children.length > 0);
-                } else {
-                    return false;
-                }
-            } else {
+            if(!node){
                 return false;
             }
-        };
-        let canDelete = function (node,m_selection) {
-            if (node) {
-                if (node.sourceType === that.project.Bills.getSourceType()) {
-                    if(node.data.type == billType.DXFY&&node.data.isAdd!=1){
+            if(node.depth()==0){//焦点行是树结构的第一层节点,灰显。
+                return false;
+            }
+            if(node.sourceType !== that.project.Bills.getSourceType()) {//焦点行是定额/量价/工料机,灰显。
+                return false;
+            }else {
+                if(node.data.type == billType.FX){//是分项,灰显。
+                    return false;
+                }
+                if(!node.preSibling){//无前兄弟,灰显
+                    return false;
+                }else if(node.preSibling.data.calcBase&&node.preSibling.data.calcBase!=""){//前兄弟有基数计算
+                    return false
+                }
+                if(node.preSibling.children.length>0){//前兄弟有子项,子项是分项,灰显。
+                    if(node.data.type==billType.FB&&node.preSibling.children[0].data.type==billType.FX){//焦点行是分部前兄弟有子项,子项是分项,灰显。
                         return false;
                     }
+                    if(node.data.type==billType.BILL&&node.preSibling.children[0].sourceType !== that.project.Bills.getSourceType()){//焦点行是清单,子项不是清单
+                        return false
+                    }
                 }
-                if(m_selection!=true&&node.sourceType === that.project.ration_glj.getSourceType()){//多选的时候不做这一项判断
+            }
+            return true;
+        };
+        let canUpMove = function (node) {
+            if(node&&node.preSibling){//有前兄弟
+                if(node.sourceType==that.project.Bills.getSourceType()&&node.data.type == billType.DXFY&&node.data.isAdd!==1){
                     return false;
                 }
-                return true;
-            } else {
-                return false;
+                return true
             }
+            return false
         };
-        let canDelete_m = function (selection) {
-            for(let i =0;i<selection.rowCount;i++){
-                if(i==0&&tree.items[selection.row].sourceType === that.project.ration_glj.getSourceType()){
-                    return false
-                }
-                if(canDelete(tree.items[selection.row+i],true)==false){
-                    return false
+        let canDownMove = function (node) {
+            if(node&&node.nextSibling){
+                if(node.sourceType==that.project.Bills.getSourceType()&&node.data.type == billType.DXFY&&node.data.isAdd!==1){
+                    return false;
                 }
+                return true;
             }
-            return true
+            return false
         };
-
-        let selections = projectObj.mainSpread.getActiveSheet().getSelections();
-        if(selections[0].rowCount==1){//选中单行
-            setButtonValid(canDelete(selected), $('#delete'));
-        }else {
-            setButtonValid(canDelete_m(selections[0]), $('#delete'));
-        }
+        
+        setButtonValid(ifCanDelete(), $('#delete'));
         setButtonValid(canUpLevel(selected), $('#upLevel'));
         setButtonValid(canDownLevel(selected), $('#downLevel'));
-        setButtonValid(selected && (selected.depth() > 0) && selected.canUpMove(), $('#upMove'));
-        setButtonValid(selected && (selected.depth() > 0) && selected.canDownMove(), $('#downMove'));
-
+        setButtonValid(canUpMove(selected) , $('#upMove'));
+        setButtonValid(canDownMove(selected), $('#downMove'));
     },
     checkCommonField: function (editingText, colSetting) {
         let value;
@@ -157,55 +186,11 @@ var projectObj = {
             return this.checkCommonField(editingText, colSetting);
         }
     },
-    /*updateAndReCalculate: function (node, fieldName, value) {
-        let project = projectObj.project, calc = new BillsCalcHelper(project), nodes = [];
-        let getNodes = function (node) {
-            let cur = node, nodes = [];
-            while (cur) {
-                nodes.push(cur);
-                cur = cur.parent;
-            }
-            return nodes;
-        }
-        if (value) {
-            value = value.toDecimal(projectObj.project.Decimal.common.quantity);
-        }
-        if (node.sourceType === projectObj.project.Bills.getSourceType()) {
-            calcFees.setFee(node.data, fieldName, value);
-            calc.calcNode(node, true);
-            nodes = getNodes(node);
-            project.Bills.updateNodes(nodes, true);
-        }
-        else if (node.sourceType === projectObj.project.VolumePrice.getSourceType()) {
-            project.beginUpdate('VolumePrice_QuantityChange');
-            project.VolumePrice.updateField(node.source, fieldName, value, false);
-            calc.calcNode(node.parent, true);
-            nodes = getNodes(node.parent);
-            project.Bills.updateNodes(nodes, false);
-            project.endUpdate();
-            nodes.push(node);
-        }
-        else if (node.sourceType === projectObj.project.Ration.getSourceType()) {
-            project.beginUpdate('Ration_QuantityChange');
-            calcFees.setFee(node.data, fieldName, value);
-            node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
-            // calcProgram.calculate的传参必须是cacheNode类型,故无法将计算放在Ration模块中。
-            project.calcProgram.calculate(node);
-            project.Ration.updateRation(node.source, false);    // 加入待存储队列
-            calc.calcNode(node.parent, true);       //
-            nodes = getNodes(node.parent);
-            project.Bills.updateNodes(nodes, false);
-            project.endUpdate();
-            nodes.push(node);
-        }
-        this.mainController.refreshTreeNode(nodes, false);
-        calc = null;
-    },*/
     updateBillsCode: function (node, value) {
         let project = projectObj.project;
         let stdMatchCode, formatCode, matchs;
         let searchStdBillsAndUpdate = function (stdCode, formatCode) {
-            let orgCode = node.data.code.substr(0, 9);
+            let orgCode = node.data.code?node.data.code.substr(0, 9):"";
             if (stdCode === orgCode || projectInfoObj.projectInfo.engineeringInfo.bill_lib.length === 0) {
                 project.Bills.updateField(node.source, 'code', formatCode, true);
                 projectObj.mainController.refreshTreeNode([node], false);
@@ -232,23 +217,27 @@ var projectObj = {
                 });
             }
         }
-        if (value&&value.length === 9 && /^[\d]+$/.test(value)) {
-            stdMatchCode = value;
-            formatCode = project.Bills.newFormatCode(stdMatchCode);
-            searchStdBillsAndUpdate(stdMatchCode, formatCode);
-        } else if (value&&value.length === 12 && /^[\d]+$/.test(value)) {
-            stdMatchCode = value.substr(0, 9);
-            matchs = project.Bills.sameStdCode(stdMatchCode, node.data.code);
-            if (matchs.indexOf(value) === -1) {
-                searchStdBillsAndUpdate(stdMatchCode, value);
-            } else if (confirm('已存在该编码的清单,是否继续?')) {
-                formatCode = project.Bills.newFormatCode(stdMatchCode, node.data.code);
+        if(node.data.type==billType.FX||node.data.type==billType.BILL){
+            if (value&&value.length === 9 && /^[\d]+$/.test(value)) {
+                stdMatchCode = value;
+                formatCode = project.Bills.newFormatCode(stdMatchCode);
                 searchStdBillsAndUpdate(stdMatchCode, formatCode);
+                return;
+            } else if (value&&value.length === 12 && /^[\d]+$/.test(value)) {
+                stdMatchCode = value.substr(0, 9);
+                matchs = project.Bills.sameStdCode(stdMatchCode, node.data.code);
+                if (matchs.indexOf(value) === -1) {
+                    searchStdBillsAndUpdate(stdMatchCode, value);
+                } else if (confirm('已存在该编码的清单,是否继续?')) {
+                    formatCode = project.Bills.newFormatCode(stdMatchCode, node.data.code);
+                    searchStdBillsAndUpdate(stdMatchCode, formatCode);
+                    return;
+                }
             }
-        } else {
-            project.Bills.updateField(node.source, 'code', value, true);
-            this.mainController.refreshTreeNode([node], false);
-        } 
+        }
+        project.Bills.updateField(node.source, 'code', value, true);
+        this.mainController.refreshTreeNode([node], false);
+
     },
     updateRationCode: function (node, value) {
         if (projectInfoObj.projectInfo.engineeringInfo.ration_lib.length === 0) {
@@ -280,30 +269,31 @@ var projectObj = {
             };*/
         }
     },
-    updateCellValue: function (node, value, colSetting) {
-        console.log(`node`);
-        console.log(node);
+    updateCellValue: function (node, value, colSetting,editingText) {
         let project = projectObj.project, fieldName = colSetting.data.field;
         if(node.sourceType==project.ration_glj.getSourceType()){
             project.ration_glj.updateFromMainSpread(value,node,fieldName);
-        }else if(treeNodeTools.isGljRation(node)){
+        }
+        else if(calcTools.isGljRation(node)){
             gljOprObj.updateRationTypeGLJ(value,node,fieldName);
-        } else if (value !== calcFees.getFee(node.data, fieldName)||fieldName == 'quantity') {//工程量需要进行转换,所以做特殊处理
-            if (fieldName === 'code' && !treeNodeTools.isVolumePrice(node)) {
+        }
+        else if (value !== calcFees.getFee(node.data, fieldName)||fieldName == 'quantity') {//工程量需要进行转换,所以做特殊处理
+            if (fieldName === 'code' && !calcTools.isVolumePrice(node)) {
                 projectObj.updateCode(node, value);
             }
             else if(fieldName ==='feeRate'){
                 project.FeeRate.updateFeeRateFromBills(value,node,fieldName);
-            }else if(fieldName ==='contain'){//编辑含量
+            }
+            else if(fieldName ==='contain'){//编辑含量
                 project.Ration.updateContain(value,node);
             }
             else if (fieldName === 'quantity' || fieldName === 'marketUnitFee' || fieldName === 'programID' ||
-                fieldName === 'subType' || fieldName === 'calcBase' || fieldName === 'feesIndex.common.unitFee'){
+                fieldName === 'subType' || fieldName === 'calcBase' || fieldName === 'isSubcontract'){
                 if (fieldName === 'quantity') {
-                    project.quantity_detail.editMainTreeNodeQuantity(value,node,fieldName);
+                    project.quantity_detail.editMainTreeNodeQuantity(value,node,fieldName,editingText);
                     return;
                 }
-                else if (fieldName === 'marketUnitFee' || fieldName === 'feesIndex.common.unitFee') {
+                else if (fieldName === 'marketUnitFee') {
                     if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("unitPrice", node))};
                 }
                 else if (fieldName === 'calcBase') {
@@ -320,17 +310,16 @@ var projectObj = {
                     }
                     // if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("totalPrice", node))};
                 };
-                node.changed = true;
-                if (fieldName == 'feesIndex.common.unitFee'){
-                    treeNodeTools.initFeeField(node, 'common');
-                    node.data.feesIndex.common.unitFee = value;
-                }
-                else if(fieldName !== 'calcBase'){
+
+                if(fieldName !== 'calcBase'){
                     node.data[fieldName] = value;
+                    node.changed = true;
                 }
+
                 project.calcProgram.calcAndSave(node);
                 gljOprObj.showRationGLJSheetData();
-            } else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
+            }
+            else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
                 node.data[fieldName] = value;
                 node.changed = true;
                 if(node.data.quantity){
@@ -351,9 +340,11 @@ var projectObj = {
                 }
                 projectObj.mainController.refreshTreeNode([node]);
             }
-        } else if(value==null && fieldName ==='feeRate'){
+        }
+        else if(value==null && fieldName ==='feeRate'){
             project.FeeRate.cleanFeeRateID(node);
-        } else {
+        }
+        else {
             projectObj.mainController.refreshTreeNode([node], false);
         }
     },
@@ -383,7 +374,7 @@ var projectObj = {
         let fieldName = projectObj.mainController.setting.cols[info.col].data.field;
         // 检查输入类型等
         let value = projectObj.checkSpreadEditingText(info.editingText, colSetting);
-        projectObj.updateCellValue(node, value, colSetting);
+        projectObj.updateCellValue(node, value, colSetting,info.editingText);
 
         // 自动行高
         const autoHeight = project.property.displaySetting.autoHeight;
@@ -426,7 +417,7 @@ var projectObj = {
                 that.project.property = projectInfoObj.projectInfo.property;
                 //that.project.calcProgram.compileAllTemps();
                 that.project.calcBase.init(that.project);
-                that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
+                // that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
                 // that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);
                 that.project.projSetting.mainGridSetting = JSON.parse(str);
@@ -475,13 +466,15 @@ var projectObj = {
                     if(col.data.field ==='quantity'){
                         col.showHint = true;
                     }
-                    // for test digit. CSLAAAAA
-                    if (col.data.field.hasSubStr("totalFee"))
-                       col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, false)
-                    else if (col.data.field.hasSubStr("unitFee"))
-                        col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, false)
-                    else if (col.data.field == "quantity")
-                        col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.quantity, false);
+
+                    // 综合单价、综合合价,小数部分应补0对齐。  CSLAAAAA
+                    // 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"))
+                            col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true)
+                    // }
+
                 });
 
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
@@ -496,10 +489,16 @@ var projectObj = {
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, that.mainSpreadRangeChanged);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, that.amountAreaNumber);
+                that.mainSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, that.onButtonClick);
                 that.loadMainSpreadContextMenu();
                 that.loadFocusLocation();
                 let endTime = +new Date();
+                socketObject.connect();//连接socket服务器
                 console.log("加载完成-----"+endTime);
+                console.log(`时间——${endTime - startTime}`);
+                that.project.projectMarkChecking();//是否需要重新进行造价计算
+                console.log(projectInfoObj.projectInfo);
+                //project.calcProgram.calcAllNodesAndSave()
             }
             else {
 
@@ -535,7 +534,7 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     disabled: function () {
                         let selected = project.mainTree.selected;
-                        if(selected.sourceType==project.Bills.getSourceType()){
+                        if(selected&&selected.sourceType==project.Bills.getSourceType()){
                             if(selected.data.type==billType.FB){
                                 return false;
                             }
@@ -553,7 +552,11 @@ var projectObj = {
                         ProjectController.addFB(project, controller);
                     },
                     visible: function(key, opt){
-                        return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                        if(project.mainTree.selected){
+                            return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                        }else {
+                            return false;
+                        }
                     }
                 },
                 "insertFX": {
@@ -561,7 +564,7 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     disabled: function () {
                         let selected = project.mainTree.selected;
-                        if(selected.sourceType==project.Bills.getSourceType()){
+                        if(selected&&selected.sourceType==project.Bills.getSourceType()){
                             if(selected.data.type==billType.FX){//焦点行是分项,有效显示
                                 return false
                             }
@@ -586,7 +589,11 @@ var projectObj = {
                         ProjectController.addFX(project, controller);
                     },
                     visible: function(key, opt){
-                        return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                        if(project.mainTree.selected){
+                            return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                        }else {
+                            return false;
+                        }
                     }
                 },
                 "insertBills": {
@@ -605,7 +612,11 @@ var projectObj = {
                         ProjectController.addBills(project, controller);
                     },
                      visible: function(key, opt){
-                         return  project.Bills.isFBFX(project.mainTree.selected)==true?false:true;//不属于分部分项的话隐藏
+                         if(project.mainTree.selected){
+                             return  project.Bills.isFBFX(project.mainTree.selected)==true?false:true;
+                         }else {
+                             return false;
+                         }
                      }
                 },
                 "insertRation": {
@@ -620,11 +631,14 @@ var projectObj = {
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
-                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
-                            return false
-                        }else {
-                            return true
+                        if(selected){
+                            if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                                return false
+                            }else {
+                                return true
+                            }
                         }
+                       return false;
                     }
                 },
                 "insertLJ": {
@@ -639,11 +653,14 @@ var projectObj = {
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
-                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
-                            return false
-                        }else {
-                            return true
+                        if(selected){
+                            if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                                return false
+                            }else {
+                                return true
+                            }
                         }
+                       return false;
                     }
                 },
                 "insertGLJ": {
@@ -667,11 +684,27 @@ var projectObj = {
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
-                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
-                            return false
-                        }else {
-                            return true
+                        if(selected){
+                            if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                                return false;
+                            }else {
+                                return true;
+                            }
                         }
+                        return false;
+                    }
+                },
+                "ZLFB": {
+                    name: "整理分部",
+                    icon: 'fa-sign-in',
+                    disabled: function () {
+                       return false;
+                    },
+                    callback: function (key, opt) {
+                        zlfb_object.getSectionInfo();
+                    },
+                    visible: function(key, opt){
+                        return true;
                     }
                 },
                 "spr1": '--------',
@@ -679,8 +712,7 @@ var projectObj = {
                     name: '删除',
                     icon: 'fa-remove',
                     disabled: function () {
-                        var selected = project.mainTree.selected;
-                        return !selected;
+                        return !ifCanDelete();
                     },
                     callback: function () {
                         $("#delete_row").modal({show:true});//弹出删除提示框;
@@ -691,9 +723,7 @@ var projectObj = {
                     name: '造价计算',
                     callback: function () {
                         $.bootstrapLoading.start();
-                        let changedNodes = project.calcProgram.calcAllNodes();
-                        project.calcProgram.saveNodes(changedNodes);
-                        $.bootstrapLoading.end();
+                        project.calcProgram.calcAllNodesAndSave();
                     }
                 }
             }
@@ -810,7 +840,132 @@ var projectObj = {
                 isTotalShowing = true;
             }, 200);
         };
+ },
+
+    onButtonClick: function (e, info) {
+        let node = projectObj.project.mainTree.items[info.row];
+        if (node.data.isSubcontract) node.data.isSubcontract = false
+        else node.data.isSubcontract = true;
+
+        node.changed = true;
+        projectObj.project.calcProgram.calcAndSave(node);
+    },
+
+    //根据节点获取行style(颜色、字体加粗)
+    getNodeColorStyle: function (node, colSetting) {
+        let colorSetting = optionsOprObj.getOption(optionsOprObj.optionsTypes.COLOROPTS);
+        let mapping = {DEFAULT: 'DEFAULT', DXFY: 'DXFY', FB: 'FB', UNLEAFBILL: 'UNLEAFBILL',
+            FX: 'FX', UNCBBILL: 'UNCBBILL', CBBILL: 'CBBILL', ZCSB: 'ZCSB'};
+        let styleMap = null;
+        //中文字段名,由于同一节点中,中文字体大小和数字字体大小不同
+        let stringFields = [
+            'code',
+            'subType',
+            'name',
+            'unit',
+            'itemCharacterText',
+            'jobContentText',
+            'adjustState',
+            'calcBase',
+            'programID',
+            'ruleText'
+        ];
+        if(!isDef(node)){
+            return null;
+        }
+        //清单大类
+        if(node.sourceType === this.project.Bills.getSourceType()){
+            //大项费用
+            //大项费用
+            if(node.data.type === billType.DXFY){
+                styleMap = mapping.DXFY;
+            }
+            //分部
+            if(node.data.type === billType.FB){
+                styleMap = mapping.FB;
+            }
+            //分项
+            else if(node.data.type === billType.FX){
+                styleMap = mapping.FX;
+            }
+            //清单
+            else if(node.data.type === billType.BILL){
+                //非叶子节点的清单
+                if(node.source.children.length > 0){
+                    styleMap = mapping.UNLEAFBILL;
+                }
+                //未使用基数计算的叶子节点的清单
+                else if(node.source.children.length === 0 && (!isDef(node.data.calcBase) || node.data.calcBase === '')){
+                    styleMap = mapping.UNCBBILL;
+                }
+                //使用基数计算的叶子节点的清单
+                else if(node.source.children.length === 0 && isDef(node.data.calcBase && node.data.calcBaseValue !== '')){
+                    styleMap = mapping.CBBILL;
+                }
+            }
+        }
+        //定额下的主材、设备
+        else if(node.sourceType === this.project.ration_glj.getSourceType()){
+            styleMap = mapping.ZCSB;
+        }
+        else {
+            styleMap = mapping.DEFAULT;
+        }
+        let styleSetting = colorSetting[styleMap];
+        let defaultSetting = colorSetting[mapping.DEFAULT];
+        if(!isDef(styleSetting)){
+            return null;
+        }
+        let style = new GC.Spread.Sheets.Style();
+        //设置style属性
+        for(let attr in styleSetting){
+            if(attr !== 'stringFont' && attr !== 'numFont'){
+                style[attr] = styleSetting[attr] === 'default' || !isDef(styleSetting[attr]) ? defaultSetting[attr] : styleSetting[attr];
+            }
+            //暂时不开放字体设置,开放的话只能每个单元格进入此方法
+           /* else {
+                if(stringFields.indexOf(colSetting.data.field) > 0){
+                    style.font = styleSetting.stringFont === 'default' || !isDef(styleSetting.stringFont) ? defaultSetting.stringFont : styleSetting.stringFont;
+                }
+                else {
+                    style.font = styleSetting.numFont === 'default' || !isDef(styleSetting.numFont) ? defaultSetting.numFont : styleSetting.numFont;
+                }
+            }*/
+        }
+        style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+        style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+        style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+        style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+        return style;
+    },
+    //大项费用则字体加粗,String 15px, Number 13px
+    getBoldFontStyle: function (node, colSetting) {
+        if(node.sourceType !== this.project.Bills.getSourceType() || node.data.type !== billType.DXFY){
+            return null;
+        }
+        let style = new GC.Spread.Sheets.Style();
+        //备注暂无字段
+        let stringFields = [
+            'code',
+            'subType',
+            'name',
+            'unit',
+            'itemCharacterText',
+            'jobContentText',
+            'adjustState',
+            'calcBase',
+            'programID',
+            'ruleText'
+        ];
+        if(stringFields.indexOf(colSetting.data.field) > 0){
+            style.font = 'bold 15px Arial';
+        }
+        else {
+            style.font = 'bold 13px Arial';
+        }
+        return style;
     }
+    
 };
 // 点击合计框中的复制
 $("body").on("click", "#total-tips a", function() {
@@ -850,7 +1005,8 @@ $('#upLevel').click(function () {
     if (selected && selected.sourceType === project.Bills.getSourceType()) {
         project.Bills.upLevelBills(selected.source);
         controller.upLevel();
-        projectObj.converseCalculateBills(orgParent);
+        controller.refreshTreeNode([orgParent]);
+        projectObj.project.calcProgram.calcBillsAndSave([selected,orgParent]);
     }
 });
 $('#downLevel').click(function () {
@@ -858,7 +1014,8 @@ $('#downLevel').click(function () {
     var selected = controller.tree.selected;
     if (selected && selected.sourceType === project.Bills.getSourceType()) {
         project.Bills.downLevelBills(selected.source);
-        controller.downLevel();       
+        controller.downLevel();
+        controller.refreshTreeNode([selected.parent]);
         projectObj.converseCalculateBills(selected.parent);
     }
 });
@@ -931,8 +1088,8 @@ $('#property_ok').click(function () {
             bills: bills
         },
 
-        reCalcBills= false,
-        reCalcRations= false;
+        reCalcBills = false,
+        reCalcRations = false;
 
     let b = parseInt($("input[name='calcFlag']:checked").val());
     if (b !== project.property.billsCalcMode) {
@@ -945,7 +1102,7 @@ $('#property_ok').click(function () {
     if (zg !== project.property.zanguCalcMode) {
         properties['property.zanguCalcMode'] = zg;
         project.property.zanguCalcMode = zg;
-        reCalcBills = true;
+        reCalcRations = true;
     };
 
     //基本信息
@@ -995,30 +1152,15 @@ $('#property_ok').click(function () {
     };
     // 重新计算树节点
     let changedNodes = [];
-    if (reCalcRations)    // 定额动,全部计算。
+    if (reCalcRations)    // 定额动,全部计算。算完先不存储,和后面的数据一起提交,一次通讯。
         changedNodes = project.calcProgram.calcAllNodes(calcAllType.catAll)
     else if (reCalcBills)  // 清单动,可以只计算清单。
         changedNodes = project.calcProgram.calcAllNodes(calcAllType.catBills);
     if (changedNodes.length > 0) {
         for (let node of changedNodes){
-            let data = {
-                // projectID: projectID,
-                ID: node.data.ID,
-                quantity: node.data.quantity,
-                calcBase: node.data.calcBase,
-                calcBaseValue: node.data.calcBaseValue,
-                marketUnitFee: node.data.marketUnitFee,
-                marketTotalFee: node.data.marketTotalFee,
-                fees: node.data.fees,
-                feeRate: node.data.feeRate,
-                feeRateID: node.data.feeRateID
-            };
-            if (node.sourceType == 'ration'){
-                rations.push(data);
-            }
-            else if (node.sourceType == 'bills'){
-                bills.push(data);
-            };
+            let data = calcTools.cutNodeForSave(node);
+            if (node.sourceType == 'ration') rations.push(data)
+            else if (node.sourceType == 'bills') bills.push(data);
         };
     };
 
@@ -1122,4 +1264,45 @@ function isSingleSelect() {//是否选中造价书中的单行
         return true;
     }
     return false;
+}
+function ifCanDelete() {
+    let selections = projectObj.mainSpread.getActiveSheet().getSelections();
+    let tree = projectObj.project.mainTree;
+    let selected = projectObj.project.mainTree.selected;
+    if(selections[0].rowCount==1){//选中单行
+        return canDelete(selected);
+    }else {
+       return canDelete_m(selections[0]);
+    }
+
+    function canDelete(node,m_selection) {
+        if (node) {
+            if (node.sourceType === projectObj.project.Bills.getSourceType()) {
+                if(node.data.type == billType.DXFY&&node.data.isAdd!=1){
+                    return false;
+                }
+            }
+            if(m_selection!=true&&node.sourceType === projectObj.project.ration_glj.getSourceType()){//多选的时候不做这一项判断
+                return false;
+            }
+            return true;
+        } else {
+            return false;
+        }
+    };
+
+    function canDelete_m(selection) {
+        for(let i =0;i<selection.rowCount;i++){
+            if(tree.items[selection.row+i]==undefined||tree.items[selection.row+i]==null){
+                return false;
+            }
+            if(i==0&&tree.items[selection.row].sourceType === projectObj.project.ration_glj.getSourceType()){
+                return false
+            }
+            if(canDelete(tree.items[selection.row+i],true)==false){
+                return false
+            }
+        }
+        return true
+    };
 }

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

@@ -80,7 +80,7 @@ var billsLibObj = {
         var findData = function (value, field, Array) {
             var i = 0;
             for (i = 0; i < Array.length; i++) {
-                if (value[field] === Array[i][field]) {
+                if (value[field] == Array[i][field]) {
                     return Array[i];
                 }
             }

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

@@ -287,11 +287,19 @@ $('#rationSearch').click(function () {
         resultSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, rationLibObj.onRationSpreadCellDoubleClick);
     };
     CommonAjax.post('/complementaryRation/api/findRation', {'user_id': userID, 'rationRepId': rationLibID, 'keyword': keyword}, function (result) {
+        //sort
+        result.sort(function (a, b) {
+            let rst = 0;
+            if(a.code > b.code) rst = 1;
+            else if(a.code < b.code) rst = -1;
+            return rst;
+        });
         var resultObj = $('#rationSearchResult'), resultSpread = null;
         resultObj.empty();
         resultObj.append(getResultHtml(result));
         $('a', resultObj).click(function () {
             resultObj.hide();
+            $(".main-data-side-d").height($(window).height() - $(".header").height() - $(".toolsbar").height() -  $(".tools-bar-height-d").height() - 202);
             $(".main-data-side-search", resultObj).height(0);
         });
         resultObj.show();

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

@@ -82,6 +82,7 @@ $("#linkGCLMX").click(function(){
 });
 
 $("#linkJSCX").click(function(){        // 计算程序
+    $.contextMenu( 'destroy', "#subSpread" );
     $("#subItems").children().hide();
     $("#subSpread").show();
     pageCCOprObj.active = false;

+ 276 - 0
web/building_saas/main/js/views/zlfb_view.js

@@ -0,0 +1,276 @@
+/**
+ * Created by zhang on 2018/1/22.
+ */
+let zlfb_object={
+    sectionInfo:null,
+    getSectionInfo:function () {
+        let controller = projectObj.mainController, project = projectObj.project;
+        let Bill = project.Bills;
+        let FBFX = Bill.getFBFXNode(controller);//取分部分项工程节点;
+        let all_sub_nodes=[],FB_nodes =[],FX_nodes =[], query={};
+        let codeMap = {};
+        let reorganize = false;
+        controller.tree.getAllSubNode(FBFX,all_sub_nodes);//取分部分项工程节点下的所有节点,不包括定额和工料机节点;
+        for(let tem_node of all_sub_nodes){
+            if(tem_node.sourceType==Bill.getSourceType()){
+                if(tem_node.data.type == billType.FB){
+                    FB_nodes.push(tem_node);
+                }
+                if(tem_node.data.type == billType.FX){
+                    FX_nodes.push(tem_node);
+                    let l_code = zlfb_object.getLibCode(tem_node.data.code);
+                    if(tem_node.data.billsLibId&&l_code!=false){
+                        reorganize= true;
+                        if(codeMap[l_code]){
+                            codeMap[l_code].push(tem_node);
+                        }else {
+                            codeMap[l_code]=[tem_node];
+                        }
+                        if(query[tem_node.data.billsLibId]){
+                            query[tem_node.data.billsLibId][l_code]=true;
+                        }else {
+                            query[tem_node.data.billsLibId]={};
+                            query[tem_node.data.billsLibId][l_code]=true;
+                        }
+                    }
+                }
+            }
+        }
+        if(reorganize==true){
+            zlfb_object.sectionInfo = {
+                'codeMap':codeMap,
+                'FB_nodes':FB_nodes,
+                'FX_nodes':FX_nodes
+            }
+            CommonAjax.post('/bills/getSectionInfo',query,function (data) {
+                if(data){
+                    zlfb_object.sectionInfo.fxMap = data.fxMap;
+                    zlfb_object.sectionInfo.sectionMap = data.sectionMap;
+                }
+                $("#zlfb").modal({show:true});
+            });
+        }else {
+            $("#zlfb").modal({show:true});
+        }
+    },
+    getLibCode:function (billCode) {//根据清单编号得到清单库中的编号
+        if(billCode&&billCode.length>=9){
+            return billCode.substr(0,9);
+        }else {
+            return false;
+        }
+    },
+    reorganizeNodes:function () {
+        let me = this;
+        let controller = projectObj.mainController, project = projectObj.project;
+        let Bill = project.Bills;
+        let FBFX = Bill.getFBFXNode(controller);//取分部分项工程节点;
+        let resort = $('#bill_resort').prop('checked'),recode=$('#bill_recode').prop('checked'),first=$('#bill_first').prop('checked');
+        let second =$('#bill_second').prop('checked'), third =$('#bill_third').prop('checked');
+        let needSelf = first==true||second==true||third==true;//需要补充分部节点;
+        $.bootstrapLoading.start();
+        if(me.sectionInfo){
+            let FX_nodes =me.sectionInfo.FX_nodes,fxMap = me.sectionInfo.fxMap,FB_nodes =me.sectionInfo.FB_nodes;
+            let codeMap = {},sectionNodeMap={},allNewNode=[],updateData={},newDataMap={};
+            let first_FX_ID = -1;
+            if(FB_nodes.length>0){
+                updateData.delete = me.getDeleteData(FB_nodes);
+                Bill.deleteAllFBNodes();
+            }
+            if(resort){
+                FX_nodes = _.sortBy(FX_nodes,'data.code');
+            }
+            for(let tem_node of FX_nodes){
+                let isStd = true;//是标准工料机
+                let l_code = me.getLibCode(tem_node.data.code);
+                let parentNode = FBFX;
+                let newCode = tem_node.data.code;
+                if(l_code!=false&&fxMap[l_code]){//能找到说明是标准工料机
+                    let tem_sectionInfo = fxMap[l_code].sectionInfo;
+                    if(first&&tem_sectionInfo['first']){//需要专业分部标题
+                        parentNode= me.createSectionNode(sectionNodeMap,tem_sectionInfo['first'],parentNode,allNewNode,newDataMap,true);
+                    }
+                    if(second&&tem_sectionInfo['second']){//需要章分部标题
+                        let isRoot = first==true?false:true;
+                        parentNode= me.createSectionNode(sectionNodeMap,tem_sectionInfo['second'],parentNode,allNewNode,newDataMap,isRoot);
+                    }
+                    if(third&&tem_sectionInfo['third']){//需要章分部标题
+                        let isRoot = first==true||second==true?false:true;
+                        parentNode= me.createSectionNode(sectionNodeMap,tem_sectionInfo['third'],parentNode,allNewNode,newDataMap,isRoot);
+                    }
+                    if(recode==true){//需要重新编号
+                        if(codeMap[l_code]){
+                            codeMap[l_code]+=1;
+                        }else {
+                            codeMap[l_code]=1;
+                        }
+                        newCode = l_code+me.getEndCode(codeMap[l_code],3);
+                    }
+                }else {//自定义分项
+                    if(needSelf==true){
+                        parentNode= me.createSectionNode(sectionNodeMap,"customer",parentNode,allNewNode,newDataMap,true);
+                    }
+                    isStd = false;
+                }
+                let nextID=-1;
+                if(needSelf==false){//如果章节信息三项都不勾选的情况下,要插在自定义分项前
+                    if(isStd==false&&first_FX_ID==-1){//如果是自定义分项,并且是第一个,要记住ID
+                        first_FX_ID = tem_node.getID();
+                    }
+                   if(isStd==true){//如果是标准的分部,则要插入到第一个自定义分部前面
+                       nextID = first_FX_ID;
+                    }
+                }
+                let newFXNode  = controller.tree.insert(parentNode.getID(), nextID,tem_node.getID());
+                let newSource = Bill.tree.insertByData(tem_node.data,parentNode.getID(), nextID, true);
+                newFXNode.source = newSource;
+                newFXNode.sourceType = project.Bills.getSourceType();
+                newFXNode.data = newSource.data;
+                allNewNode.push(newFXNode);
+                newFXNode.data.code = newCode;
+                newFXNode.data.ParentID = parentNode.getID();
+                newFXNode.data.NextSiblingID=nextID;
+                newDataMap[newFXNode.getID()]={
+                    code:newCode,
+                    ParentID:parentNode.getID(),
+                    NextSiblingID:nextID
+                }
+                if(newFXNode.preSibling){
+                    newFXNode.preSibling.data.NextSiblingID = newFXNode.getID();
+                    newDataMap[newFXNode.preSibling.getID()].NextSiblingID=newFXNode.getID();
+                }
+                //生成定额或工料机节点
+                if(tem_node.children.length>0){
+                    me.addSubNode(newFXNode,tem_node.children,allNewNode,controller)
+                }
+            };
+            me.submitRequest(newDataMap,allNewNode,updateData,FBFX,controller);
+            $.bootstrapLoading.end();
+        }else {
+            $.bootstrapLoading.end();
+        }
+    },
+    addSubNode:function (parentNode,oldChildren,allNewNode,controller) {
+        for(let c of oldChildren){
+            let newChild = controller.tree.insert(parentNode.getID(), -1,c.getID());
+            newChild.source = c.data;
+            newChild.sourceType = c.sourceType;
+            newChild.data = c.data;
+            allNewNode.push(newChild);
+            if(c.children.length>0){
+                zlfb_object.addSubNode(newChild,c.children,allNewNode,controller);
+            }
+        }
+    },
+    getDeleteData:function (FB_nodes) {
+        let fbIDs=[];
+        for(let fb of FB_nodes){
+            fbIDs.push(fb.getID());
+        }
+        return fbIDs;
+    },
+    createSectionNode:function (sectionNodeMap,ID,parentNode,allNewNode,newDataMap,isRoot) {
+        let sectionMap = zlfb_object.sectionInfo.sectionMap;
+        let controller = projectObj.mainController;
+        if(sectionNodeMap[ID]){//如果这个节点已经存在
+            parentNode = sectionNodeMap[ID];
+        }else {//不存在就生成一个
+            let nodeID = uuid.v1();
+            let nextID=-1;
+            if(isRoot==true&&ID!='customer'&&sectionNodeMap['customer']){//如果自定义分部存在,插入到自定文分部前面
+                nextID=sectionNodeMap['customer'].getID();
+            }
+            let newNode  = controller.tree.insert(parentNode.getID(), nextID,nodeID);
+            let data ={
+                ID:nodeID,
+                projectID:parseInt(projectObj.project.ID()),
+                ParentID:parentNode.getID(),
+                NextSiblingID:nextID,
+                type:billType.FB
+            };
+            if(newNode.preSibling){
+                newDataMap[newNode.preSibling.getID()].NextSiblingID=newNode.getID();
+                newNode.preSibling.data.NextSiblingID=newNode.getID();
+            }
+            if(ID=='customer'){
+                data.name = '补充分部';
+            }else {
+                if(sectionMap[ID]==undefined){
+                    console.log(ID);
+                }
+                data.code = sectionMap[ID].code;
+                data.name = sectionMap[ID].name;
+            }
+
+            let newSource = projectObj.project.Bills.tree.insertByData(data,parentNode.getID(), nextID, true);
+            newNode.source = newSource;
+            newNode.sourceType = projectObj.project.Bills.getSourceType();
+            newNode.data = newSource.data;
+            sectionNodeMap[ID]=newNode;
+            parentNode = newNode;
+            allNewNode.push(newNode);
+            newDataMap[nodeID]=data;
+        }
+        return parentNode;
+    },
+    getEndCode:function (number,length) {
+        let preString = '000000000000';
+        preString = preString+number;
+        return preString.substr(preString.length-length,length);
+    },
+    submitRequest:function(newDataMap,allNewNode,updateData,FBFX,controller){
+        for(let ID in newDataMap){ //生成更新数据
+            if(newDataMap[ID].type==billType.FB){//分部类型是插入
+                if(updateData['create']){
+                    updateData['create'].push(newDataMap[ID]);
+                }else {
+                    updateData['create']=[newDataMap[ID]];
+                }
+            }else {
+                if(updateData['update']){
+                    let u_data = {
+                        ID:ID,
+                        data:newDataMap[ID]
+                    };
+                    updateData['update'].push(u_data);
+                }else {
+                    let u_data = {
+                        ID:ID,
+                        data:newDataMap[ID]
+                    };
+                    updateData['update'] = [u_data];
+                }
+            }
+        }
+        updateData.projectID = FBFX.data.projectID;
+        updateData.user_id = userID;
+        console.log(updateData);
+        CommonAjax.post('/bills/reorganizeFBFX',updateData,function (data) {
+            console.log(data);
+        },function () {
+            //errorCallback
+        });
+        controller.sheet.addRows(1, allNewNode.length);
+        for(let c of FBFX.children){
+            TREE_SHEET_HELPER.massOperationSheet(controller.sheet, function () {
+                TREE_SHEET_HELPER.refreshTreeNodeData(controller.setting, controller.sheet, [c], true);
+                controller.sheet.showRow(c.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+            });
+        }
+        cbTools.refreshFormulaNodes();
+        console.log(newDataMap);
+        console.log(allNewNode);
+    }
+}
+
+
+$(function () {
+    $('#zlfb_confirm').click(function (){
+        $("#zlfb").modal('hide');
+        zlfb_object.reorganizeNodes();
+    });
+    $('#zlfb').on('hidden.bs.modal', function (e) {
+        zlfb_object.sectionInfo=null;
+    })
+
+})

+ 1 - 0
web/building_saas/pm/html/project-management.html

@@ -503,6 +503,7 @@
 <script src="/public/web/date_util.js"></script>
 <script src="/public/web/tree_table/tree_table.js"></script>
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+<script src="/lib/JSExpressionEval_src/Date.js"></script>
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_main.js" charset="UTF-8"></script>
 <script src="/web/building_saas/pm/js/pm_gc.js"></script>

+ 2 - 3
web/building_saas/pm/js/pm_gc.js

@@ -233,9 +233,8 @@ function v_getFiles(type, files){
     for(let i = 0, len = files.length; i < len; i ++){
         let recName = type === fileType.unitPriceFile ?  files[i].name + '单价文件' : files[i].name + '费率文件';
         let fileId = type === fileType.unitPriceFile ? files[i].id : files[i].ID;
-        let recTime = new Date();
-        let recTimeA = recTime.Format('yyyy-MM-dd');
-        let recTimeB = recTime.Format('hh:mm:ss');
+        let recTimeA = formatDate(new Date(files[i].deleteInfo.deleteDateTime), 'yyyy-MM-dd');
+        let recTimeB = formatDate(new Date(files[i].deleteInfo.deleteDateTime), 'HH:mm:ss');
         html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
     }
     return html;

+ 6 - 10
web/building_saas/pm/js/pm_main.js

@@ -225,7 +225,6 @@ $(document).ready(function() {
                 updateObj.updateData.ID = fileDelObj.id;
             }
             updateObj.fileType = fileDelObj.fileType;
-            console.log(updateObj);
             a_updateFiles([updateObj], function () {
                 fileDelObj = null;
                 $('#fileDelCancel').click();
@@ -366,7 +365,7 @@ $(document).ready(function() {
         //获取建设项目
         let selected = Tree.selected();
         let projs = getProjs(selected);
-        setProjOptions(projs);
+        setProjOptions(projs, selected);
        $($("input[name='valuation_type']")[0]).click();
     });
 
@@ -432,7 +431,6 @@ $(document).ready(function() {
         let dialog = $('#del');
         if (Tree) {
             updateData = GetDeleteUpdateData(Tree.selected());
-            console.log(updateData);
             UpdateProjectData(updateData, function () {
                 dialog.modal('hide');
                 Tree.removeNode(Tree.selected());
@@ -487,7 +485,6 @@ $(document).ready(function() {
 
     // 移动到操作
     $('#move-to-confirm').click(function () {
-        console.log(111);
         let updateData = null;
         let dialog = $('#move-to-dialog');
         let target = GetTargetTreeNode($.fn.zTree.getZTreeObj('treeDemo'));
@@ -909,7 +906,6 @@ function AddSiblingsItem(selected, name, property, type, callback) {
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
                         Tree.addNodeData(data.updateData, parent, next);
-                        console.log(selected);
                     }
                 });
                 callback();
@@ -1031,13 +1027,14 @@ function setFileOptions(projID){
 }
 
 //建设项目下拉框
-function setProjOptions(projs){
+function setProjOptions(projs, selected){
     $("#poj-name-list").empty();
     $("#poj-name").val("");
     if(projs.length > 0){
-        $("#poj-name").val(projs[0].data.name);
-        setFileOptions(projs[0].data.ID);
-        setEngOptions(projs[0].data.ID);
+        let firstProj = selected && selected.data.projType === projectType.project ? selected: projs[0];
+        $("#poj-name").val(firstProj.data.name);
+        setFileOptions(firstProj.data.ID);
+        setEngOptions(firstProj.data.ID);
         for(let i = 0, len = projs.length; i < len; i++){
             let proj = $("<button>").val(projs[i].data.ID).text(projs[i].data.name);
             proj.addClass("dropdown-item");
@@ -1845,7 +1842,6 @@ function bindEvents_file_table(jqS, usedObj, targetBody, type){
                     $(jqS + ' div:eq(0)').show();
                     $(jqS + ' div:eq(1)').hide();
                 });
-                console.log(updateObj);
             }
             let newDispName = newName + postFix;
             $(jqS + ' div:eq(0)')[0].childNodes[0].textContent = newDispName;