Browse Source

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

TonyKang 7 năm trước cách đây
mục cha
commit
24fe02a7da
33 tập tin đã thay đổi với 1324 bổ sung465 xóa
  1. 2 1
      .gitignore
  2. 1 2
      modules/complementary_glj_lib/models/gljModel.js
  3. 53 26
      modules/glj/models/glj_list_model.js
  4. 23 13
      modules/glj/models/unit_price_model.js
  5. 18 0
      modules/main/facade/decimal_facade.js
  6. 2 1
      modules/main/facade/prj_properties_facade.js
  7. 4 3
      modules/pm/models/project_model.js
  8. 20 3
      modules/ration_glj/controllers/ration_glj_controller.js
  9. 7 7
      modules/ration_glj/facade/glj_calculate_facade.js
  10. 51 10
      modules/ration_glj/facade/ration_glj_facade.js
  11. 1 0
      modules/ration_glj/routes/ration_glj_route.js
  12. 3 0
      public/web/sheet/sheet_common.js
  13. 16 0
      public/web/tree_table/tree_table.js
  14. 51 45
      web/building_saas/css/main.css
  15. 0 1
      web/building_saas/glj/js/composition_spread.js
  16. 11 0
      web/building_saas/glj/js/project_glj.js
  17. 38 8
      web/building_saas/main/html/main.html
  18. 2 0
      web/building_saas/main/js/models/bills.js
  19. 83 35
      web/building_saas/main/js/models/calc_program.js
  20. 18 2
      web/building_saas/main/js/models/main_consts.js
  21. 0 7
      web/building_saas/main/js/models/ration.js
  22. 54 12
      web/building_saas/main/js/models/ration_glj.js
  23. 1 1
      web/building_saas/main/js/views/calc_program_manage.js
  24. 5 3
      web/building_saas/main/js/views/calc_program_view.js
  25. 124 29
      web/building_saas/main/js/views/glj_view.js
  26. 15 1
      web/building_saas/main/js/views/glj_view_contextMenu.js
  27. 12 0
      web/building_saas/main/js/views/main_tree_col.js
  28. 1 1
      web/building_saas/main/js/views/project_info.js
  29. 7 7
      web/building_saas/main/js/views/project_property_decimal_view.js
  30. 54 16
      web/building_saas/main/js/views/project_view.js
  31. 4 2
      web/building_saas/main/js/views/sub_view.js
  32. 51 37
      web/building_saas/pm/html/project-management.html
  33. 592 192
      web/building_saas/pm/js/pm_main.js

+ 2 - 1
.gitignore

@@ -3,4 +3,5 @@ node_modules/
 dist/
 .idea/
 tmp/
-test/unit/logs
+test/unit/logs
+*.log

+ 1 - 2
modules/complementary_glj_lib/models/gljModel.js

@@ -262,11 +262,10 @@ class GljDao {
      */
     async getComponent(gljId) {
         let result = [];
-        let libGljData = await complementaryGljModel.find({ID: gljId});
+        let libGljData = await complementaryGljModel.findOne({ID: gljId});
         if (libGljData === null || libGljData.component.length <= 0) {
             return result;
         }
-
         // 标准工料机库
         let componentIdListStd = [];
         // 补充工料机库

+ 53 - 26
modules/glj/models/glj_list_model.js

@@ -17,6 +17,7 @@ import MixRatioModel from "./mix_ratio_model";
 import GljModel from "../../complementary_glj_lib/models/gljModel";
 const ProjectModel = require('../../pm/models/project_model').project;
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
+import decimal_facade from "../../main/facade/decimal_facade";
 
 class GLJListModel extends BaseModel {
 
@@ -75,8 +76,11 @@ class GLJListModel extends BaseModel {
      */
     async getListByProjectId(projectId, unitPriceFileId) {
         let gljData = null;
+        let decimal =await decimal_facade.getProjectDecimal(projectId);
+        let quantity_decimal = decimal&&decimal.glj.quantity?decimal.glj.quantity:6;//取消耗量保留小数据位,默认6位
         let mixRatioConnectData = {};
         let mixRationMap={};
+        let keyMap={};
         try {
             // 首先获取对应标段下所有的项目工料机数据
             let condition = {project_id: projectId};
@@ -96,6 +100,8 @@ class GLJListModel extends BaseModel {
             let gljIdList = [];
             for(let tmp of gljData) {
                 gljIdList.push(tmp.id);
+                let c_key = this.getIndex(tmp,['code','name','specs','unit','type']);
+                keyMap[tmp.id] = c_key; //工料机ID和连接key的对照表;
             }
             // 从定额工料机库中获取消耗量
             condition = {
@@ -104,22 +110,25 @@ class GLJListModel extends BaseModel {
             };
             let quantityData = await RationGLJFacade.getQuantityByProjectGLJ(condition);
             let quantityList = {};
-            // 整理数据
+            // 整理数据 得到总定额消耗量
             for (let tmp of quantityData) {
                 let tmpNum = parseFloat(tmp.rationQuantity);
                 tmpNum = isNaN(tmpNum) ||tmpNum==0? 1 : tmpNum;
-                if (quantityList[tmp.projectGLJID] === undefined) {
-                    quantityList[tmp.projectGLJID] = tmp.quantity * tmpNum;
+                let tmp_con_key = keyMap[tmp.projectGLJID];
+
+                if (quantityList[tmp_con_key] === undefined) {
+                    quantityList[tmp_con_key] = scMathUtil.roundTo(tmp.quantity * tmpNum,-quantity_decimal);
                 } else {
-                    quantityList[tmp.projectGLJID] += tmp.quantity * tmpNum;
+                    quantityList[tmp_con_key] = scMathUtil.roundTo(quantityList[tmp_con_key]+tmp.quantity * tmpNum,-quantity_decimal);
                 }
             }
             // 整理获取有组成物的项目工料机的数据
             let connect_keys = [];
             for(let tmp of gljData) {
-                // 有组成物的类型且消耗量大于0才查找
-                if (quantityList[tmp.id] !== undefined) {
-                   let key = this.getIndex(tmp,['code','name','specs','unit','type']);
+                // 有组成物的类型才查找
+                let key = keyMap[tmp.id];
+                if (quantityList[key]!=undefined&&(tmp.type === GLJTypeConst.CONCRETE || tmp.type === GLJTypeConst.MORTAR ||
+                    tmp.type === GLJTypeConst.MIX_RATIO || tmp.type === GLJTypeConst.GENERAL_MACHINE)){
                     connect_keys.push(key);
                 }
             }
@@ -132,11 +141,18 @@ class GLJListModel extends BaseModel {
                 let mixRatioList = await mixRatioModel.findDataByCondition(condition, null, false);
                 for (let tmp of mixRatioList) {
                    let t_index = tmp.connect_key;
-                    let consumption=parseFloat(tmp.consumption);
-                    totalComposition[t_index] = totalComposition[t_index] === undefined ? consumption :
+                   let consumption=parseFloat(tmp.consumption);
+                   let m_index = this.getIndex(tmp,['code','name','specs','unit','type']);
+                   let r_quantity = quantityList[t_index]?quantityList[t_index]:0;
+                   if(quantityList[m_index]!==undefined){
+                       quantityList[m_index]=quantityList[m_index]+r_quantity*consumption;
+                   }else {
+                       quantityList[m_index] = r_quantity*consumption;
+                   }
+                    quantityList[m_index] = scMathUtil.roundTo(quantityList[m_index],-quantity_decimal);
+                /*    totalComposition[t_index] = totalComposition[t_index] === undefined ? consumption :
                         totalComposition[t_index] + consumption;
-                    totalComposition[t_index] = scMathUtil.roundTo(totalComposition[t_index], -4);
-
+                    totalComposition[t_index] = scMathUtil.roundTo(totalComposition[t_index], -quantity_decimal);*/
                     if (mixRatioData[t_index] !== undefined) {
                         mixRatioData[t_index].push(tmp);
                     } else {
@@ -209,11 +225,11 @@ class GLJListModel extends BaseModel {
             let gljId = glj.glj_id + '';
             let projectGljId = glj.id + '';
             // 消耗量赋值
-            glj.quantity = quantityList[projectGljId] !== undefined ? quantityList[projectGljId] : 0;
+         /*   glj.quantity = quantityList[projectGljId] !== undefined ? quantityList[projectGljId] : 0;
             glj.quantity = totalComposition[g_index] !== undefined ? totalComposition[g_index] : glj.quantity;
             glj.quantity = compositionConsumption[g_index] !== undefined ?  glj.quantity + compositionConsumption[g_index] : glj.quantity;
-            glj.quantity = scMathUtil.roundTo(parseFloat(glj.quantity), -3);
-
+            glj.quantity = scMathUtil.roundTo(parseFloat(glj.quantity), -3);*/
+            glj.quantity = quantityList[g_index]?quantityList[g_index]:0;
             // 组成物数据
             gljList[index].ratio_data = mixRatioData[g_index] !== undefined ? mixRatioData[g_index] : [];
             //因为schema中设置base_price 为string 类型,所以要通过中间变量转换为数字再做计算,不然会自动变成字符串类型
@@ -281,6 +297,7 @@ class GLJListModel extends BaseModel {
                 throw '没有对应的单价文件';
             }
             let CompositionGLJ=[];
+            let unitPriceModel = new UnitPriceModel();
             // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物(前提是没有对应的项目工料机数据)
             if (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
                 data.type === GLJTypeConst.MIX_RATIO || data.type === GLJTypeConst.GENERAL_MACHINE) {
@@ -289,11 +306,20 @@ class GLJListModel extends BaseModel {
                     await this.compositionInit(data, unitPriceFileId);
                 }
                 CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
+                if(isAddProjectGLJ==false&&CompositionGLJ.length==0){//如果不是新增,并且是有组成物的类型但又没有发现组成物的情况下,有可能是错误数据,重新在库中查找一下组成物,有则插入
+                    await this.compositionInit(data, unitPriceFileId);
+                    CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
+
+                    if(CompositionGLJ.length>0){//如果这次发现又有组成物了,则把旧的单价数据删除,在后面的操作中会重新增加
+                        let de_condition ={unit_price_file_id: unitPriceFileId,code:data.code,name:data.name,unit:data.unit,type:data.type};
+                        data.specs!=null&&data.specs!=undefined&&data.specs!=""?de_condition.specs = data.specs:de_condition;
+                        await unitPriceModel.db.delete(de_condition);
+                    }
+                }
             }
             projectGljData.subList=CompositionGLJ;
 
             // 新增单价文件
-            let unitPriceModel = new UnitPriceModel();
             let [unitPriceInsertData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
 
             if (!unitPriceInsertData) {
@@ -350,7 +376,7 @@ class GLJListModel extends BaseModel {
         //查找单价信息,有则返回,没有则新增并返回
         let unitPriceFileId = unitPriceFile.id;
         let unitPriceModel = new UnitPriceModel();
-        let [unitPriceData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
+        let [unitPriceData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId,"modify");
         let gljData={};
         if(isAdd){ //如果是新增,则新增一条新的项目工料机
             data.code = unitPriceData.code;
@@ -448,7 +474,7 @@ class GLJListModel extends BaseModel {
             let unitPriceModel = new UnitPriceModel();
 
             let gljCount = gljListData.length;
-            let [unitPriceData, isAdd] = await unitPriceModel.addUnitPrice(updateData, unitPriceFileId, gljCount);
+            let [unitPriceData, isAdd] = await unitPriceModel.addUnitPrice(updateData, unitPriceFileId,"modify", gljCount);
 
             // 判断是否已存在对应数据
             let includeField = [
@@ -534,7 +560,6 @@ class GLJListModel extends BaseModel {
         // 查找对应组成物的项目工料机数据
         let indexs=['code','name','specs','unit','type'];
         let [projectGljList, compositionGljList] = await this.getCompositionGLJList(gljId, projectId, indexs, fromTable);
-
         // 整理配合比待插入数据
         let mixRatioInsertData = [];
         for (let tmp of compositionGljList) {
@@ -556,13 +581,16 @@ class GLJListModel extends BaseModel {
 
         // 插入配合比表
         // 因为有可能项目工料机与单价数据已存在,但配合比数据不存在,所以先插入配合比,后续判断如果存在项目工料机则可以省下数据库操作
-        let mixRatioModel = new MixRatioModel();
-        let addMixRatioResult = await mixRatioModel.add(mixRatioInsertData);
-        if (!addMixRatioResult) {
-            throw '组成物插入单价数据失败!';
+        if(mixRatioInsertData.length>0){
+            let mixRatioModel = new MixRatioModel();
+            let addMixRatioResult = await mixRatioModel.add(mixRatioInsertData);
+            if (!addMixRatioResult) {
+                throw '组成物插入单价数据失败!';
+            }
         }
+        let pglj_length = projectGljList instanceof Array ? projectGljList.length:Object.getOwnPropertyNames(projectGljList).length;
         // 如果已经存在则后续操作停止
-        if(Object.getOwnPropertyNames(projectGljList).length === compositionGljList.length) {
+        if(pglj_length === compositionGljList.length) {
             return
         }
 
@@ -675,9 +703,8 @@ class GLJListModel extends BaseModel {
         // 获取对应的组成物数据
         let gljListModel = fromTable === 'std' ? new STDGLJLibGLJListModel() : new GljModel();
         let componentGljList = await gljListModel.getComponent(gljId);
-
         if (componentGljList.length <= 0) {
-            throw '不存在对应的组成物';
+            return [{},[]];
         }
 
         let codeList = [];
@@ -726,7 +753,7 @@ class GLJListModel extends BaseModel {
         let typeList = [];
         let unitList = [];
         if(mixRatios.length<=0){
-            throw  '不存在对应的组成物';
+            return [[],[],[]];
         }
         let mixRatioData={};
         for(let tmp of mixRatios) {

+ 23 - 13
modules/glj/models/unit_price_model.js

@@ -80,7 +80,7 @@ class UnitPriceModel extends BaseModel {
      * @param {Number} gljCount
      * @return {Promise} 返回数据以及是否新增
      */
-    async addUnitPrice(data, unitPriceFileId, gljCount = 0) {
+    async addUnitPrice(data, unitPriceFileId,operation='add', gljCount = 0) {
         if (data.original_code===undefined||data.code === undefined || data.project_id === undefined || data.name === undefined
             || data.market_price === undefined) {
             return [null, false];
@@ -88,7 +88,12 @@ class UnitPriceModel extends BaseModel {
         // 先查找是否有原始code相同的记录
         let unitPriceData = await this.findDataByCondition({original_code: data.original_code, unit_price_file_id: unitPriceFileId}, null, false);
         // 如果有记录,判断是否存在一样的名称,单位...等,有则直接返回数据
-        let unitPrice =  this.isPropertyInclude(unitPriceData,['name','specs','unit','type'],data);
+        let unitPrice=null;
+        if(operation=='add'){//新增操作时,要把code也一起判断,是否完全一样
+            unitPrice =  this.isPropertyInclude(unitPriceData,['code','name','specs','unit','type'],data);
+        }else {//修改操作时,code不用加入判断,因为code是需要改变的
+            unitPrice =  this.isPropertyInclude(unitPriceData,['name','specs','unit','type'],data);
+        }
         if(unitPrice){
             return [unitPrice, false];
         }
@@ -111,11 +116,12 @@ class UnitPriceModel extends BaseModel {
             unit:data.unit,
             type: data.type,
             short_name: data.shortName !== undefined ? data.shortName : '',
-            glj_id: data.glj_id
+            glj_id: data.glj_id,
+            is_add:0
         };
-
-        // 如果原始编码能找到,但不存在一样的编号,名称,单位.更改 等,更改code和添加新增标记
-        if (unitPriceData&&unitPriceData.length>0) {
+        if(data.from=='cpt'){//如果是来自补充工料机,则都添加新增标记
+            insertData.is_add=1;
+        }else if (unitPriceData&&unitPriceData.length>0) {// 如果原始编码能找到,但不存在一样的编号,名称,单位.型号等,更改code和添加新增标记
             insertData.code = data.original_code+"-"+unitPriceData.length;
             insertData.is_add=1;
         }
@@ -322,21 +328,27 @@ class UnitPriceModel extends BaseModel {
         currentUnitList = JSON.parse(currentUnitList);
 
         let codeList = [];
+        let nameList =[];
         for (let tmp of currentUnitList) {
             if (codeList.indexOf(tmp.code) >= 0) {
                 continue;
             }
             codeList.push(tmp.code);
+            if(nameList.indexOf(tmp.name)>=0){
+                continue
+            }
+            nameList.push(tmp.name);
         }
 
-        // 查找即将更替的单价文件是否存在对应的工料机数据
-        let condition = {unit_price_file_id: changeUnitPriceId, code: {"$in": codeList}};
-        let targetUnitList = await this.findDataByCondition(condition, null, false, 'code');
+        // 查找即将更替的单价文件是否存在对应的工料机数据 -- (这里只根据code和名称初步过滤,因为其它的几项更改的概率不大,在下一步的比较中再精确匹配)
+        let condition = {unit_price_file_id: changeUnitPriceId, code: {"$in": codeList},name:{"$in": nameList}};
+        let targetUnitList = await this.findDataByCondition(condition, null, false, ['code','name','specs','unit','type']);
 
         // 如果没有重叠的数据则原有的数据都复制一份
         let insertData = [];
         for (let tmp of currentUnitList) {
-            if (targetUnitList !== null && targetUnitList[tmp.code] !== undefined) {
+            let t_index = this.getIndex(tmp,['code','name','specs','unit','type']);
+            if (targetUnitList !== null && targetUnitList[t_index] !== undefined) {
                 continue;
             }
             // 删除原有id信息
@@ -345,9 +357,7 @@ class UnitPriceModel extends BaseModel {
             tmp.unit_price_file_id = changeUnitPriceId;
             insertData.push(tmp);
         }
-
-        return insertData.length > 0 ? this.add(currentUnitList) : true;
-
+        return insertData.length > 0 ? this.add(insertData) : true;
     }
 
 

+ 18 - 0
modules/main/facade/decimal_facade.js

@@ -0,0 +1,18 @@
+/**
+ * Created by zhang on 2017/11/22.
+ */
+let projectsModel = require("../../pm/models/project_schema");
+
+
+module.exports ={
+    getProjectDecimal:getProjectDecimal
+}
+
+async function getProjectDecimal(projectID) {
+    let decimal = null;
+    let project =await projectsModel.findOne({ID:projectID});
+    if(project){
+        decimal = project.property.decimal
+    }
+    return decimal;
+}

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

@@ -5,6 +5,7 @@ let mongoose = require("mongoose");
 let prj_prop_mdl = mongoose.model("project_property");
 let std_prj_prop_mdl = mongoose.model("cfg_prj_property");
 
+
 module.exports = {
     createPrjProperties: createPrjProperties,
     removePrjProperties : removePrjProperties,
@@ -126,4 +127,4 @@ function addOrChangePropertyWithCallBack(prjId, newItem, cb) {
 
 function removeOnePropertyWithCallBack(prjId, key, cb) {
     prj_prop_mdl.update({"projectID": prjId}, {"$pull": {"properties": {"key": key}}}, cb);
-}
+}

+ 4 - 3
modules/pm/models/project_model.js

@@ -33,6 +33,8 @@ const defaultDecimal = {
     ration: {quantity: 3, unitPrice: 2, totalPrice: 2},
     glj: {quantity: 3, unitPrice: 2},
     feeRate: 2,
+    quantity_detail: 4,
+    process: 6
 };
 
 let ProjectsDAO = function(){};
@@ -77,9 +79,8 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callbac
             if (data.updateData.name !== undefined) {
                 data.updateData.name = data.updateData.name.trim();
             }
-
             if (data.updateType === 'update') {
-                Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
+                Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
             } else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['createDateTime'] = new Date();
@@ -126,7 +127,7 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callbac
                 }
                 newProject.save(async function (err, result) {
                     if (!err && result._doc.projType === projectType.tender) {
-                        newProjController.copyTemplateData(data.updateData.property, newProject.ID, updateAll);
+                        newProjController.copyTemplateData(result._doc.property, newProject.ID, updateAll);
                     } else {
                         updateAll(err);
                     }

+ 20 - 3
modules/ration_glj/controllers/ration_glj_controller.js

@@ -13,7 +13,8 @@ module.exports={
     addGLJ:addGLJ,
     replaceGLJ:replaceGLJ,
     mReplaceGLJ:mReplaceGLJ,
-    updateRationGLJByEdit:updateRationGLJByEdit
+    updateRationGLJByEdit:updateRationGLJByEdit,
+    getGLJClass:getGLJClass
 }
 function createRationGLJ() {
     let gls = mongoose.model('ration_glj');
@@ -102,7 +103,6 @@ async function mReplaceGLJ(req, res){
     try {
         let data = req.body.data;
         data = JSON.parse(data);
-        console.log(data);
         let mresult= await ration_glj_facade.mReplaceGLJ(data);
         result.data=mresult;
     }catch (err){
@@ -128,5 +128,22 @@ async  function updateRationGLJByEdit(req, res) {
         result.message = err.message;
     }
     res.json(result);
-    
+}
+
+async  function getGLJClass(req, res) {
+    let result={
+        error:0
+    }
+    try {
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let info = await ration_glj_facade.getLibInfo(req);
+        let tresult= await ration_glj_facade.getGLJClass(info,data);
+        result.data=tresult;
+    }catch (err){
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+    }
+    res.json(result);
 }

+ 7 - 7
modules/ration_glj/facade/glj_calculate_facade.js

@@ -28,7 +28,7 @@ let stateSeq ={
 }
 
 
-async function calculateQuantity(query,isMarkPriceAjust){
+async function calculateQuantity(query,noNeedCal){
     try {
          let  result ={
              glj_result:[],
@@ -51,11 +51,11 @@ async function calculateQuantity(query,isMarkPriceAjust){
                  }
          }
          for(let i =0;i<gljList.length;i++ ){
-             let r = await calculateQuantityPerGLJ(gljList[i],i,coeList,assList,adjustState,isMarkPriceAjust);
+             let r = await calculateQuantityPerGLJ(gljList[i],i,coeList,assList,adjustState,noNeedCal);
              result.glj_result.push(r);
          }
 
-        if(isMarkPriceAjust==null){
+        if(noNeedCal==null){
             await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
         }
          adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
@@ -85,8 +85,8 @@ function generateUpdateTasks(result) {
 }
 
 
-async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,isMarkPriceAjust) {
-    let quantity =  glj.quantity;
+async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,noNeedCal) {
+    let quantity =  scMathUtil.roundTo(parseFloat(glj.quantity),-6);
     let result={
         query:{
             ID:glj.ID,
@@ -97,9 +97,9 @@ async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,isM
         }
     };
     try {
-        if(isMarkPriceAjust==null){
+        if(noNeedCal==null){
             if(!glj._doc.hasOwnProperty('customQuantity')||glj.customQuantity==null){
-                quantity =glj.rationItemQuantity;
+                quantity =scMathUtil.roundTo(parseFloat(glj.rationItemQuantity),-6);
                 quantity =calculateAss(quantity,assList,glj);
                 quantity = calculateQuantityByCoes(quantity,coeList,glj);
             }else {

+ 51 - 10
modules/ration_glj/facade/ration_glj_facade.js

@@ -21,6 +21,7 @@ let logger = require("../../../logs/log_helper").logger;
 import stdgljutil  from "../../../public/cache/std_glj_type_util";
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
 import GljDao from "../../complementary_glj_lib/models/gljModel";
+import {complementaryGljModel, stdGljModel, gljClassModel} from "../../complementary_glj_lib/models/schemas";
 
 
 module.exports={
@@ -33,7 +34,8 @@ module.exports={
     addGLJ:addGLJ,
     replaceGLJ:replaceGLJ,
     mReplaceGLJ:mReplaceGLJ,
-    updateRationGLJByEdit:updateRationGLJByEdit
+    updateRationGLJByEdit:updateRationGLJByEdit,
+    getGLJClass:getGLJClass
 }
 
 let operationMap={
@@ -201,7 +203,9 @@ async function getInfoFromProjectGLJ(ration_glj) {
              marketPrice:pg.unit_price.market_price,
              adjustPrice:pg.adjust_price,
              isEstimate:pg.is_evaluate,
-             isMixRatio:true
+             isMixRatio:true,
+             isAdd:pg.unit_price.is_add,
+             GLJID:pg.glj_id
          }
          temRationGLJs.push(tem);
      }
@@ -568,6 +572,7 @@ async function addGLJ(rgList) {
        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;
        g.ID=uuidV1();
@@ -591,13 +596,18 @@ async function replaceGLJ(data) {
     let rdata={};
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(data));
+    data.projectGLJID=result.id;
+    let updateResult=await ration_glj.findOneAndUpdate({ID:data.ID,projectID:data.projectID},data);//更新定额工料机
+    //组装回传数据
     data.marketPrice=result.unit_price.market_price;
     data.adjustPrice=result.unit_price.base_price;
     data.basePrice=result.unit_price.base_price;
-    data.projectGLJID=result.id;
+    data.isAdd=result.unit_price.is_add;
     data.isEstimate=result.is_evaluate;
-    let updateResult=await ration_glj.findOneAndUpdate({ID:data.ID,projectID:data.projectID},data);
-    let stateResult =  await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID});
+    if(result.hasOwnProperty('subList')&&result.subList.length>0){
+        data.subList=getMixRatioShowDatas(result.subList);
+    }
+    let stateResult =  await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},true);
     rdata.data=data;
     rdata.adjustState=stateResult.adjustState;
     return rdata;
@@ -606,13 +616,18 @@ async function mReplaceGLJ(data) {
     let mresult={};
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(data.doc));
+    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});
+
     data.doc.marketPrice=result.unit_price.market_price;
     data.doc.adjustPrice=result.unit_price.base_price;
     data.doc.basePrice=result.unit_price.base_price;
-    data.doc.projectGLJID=result.id;
+    data.doc.isAdd=result.unit_price.is_add;
     data.doc.isEstimate=result.is_evaluate;
-    let rationList=await ration_glj.distinct('rationID',data.query);
-    let updateResult=await ration_glj.update(data.query,data.doc,{multi: true});
+    if(result.hasOwnProperty('subList')&&result.subList.length>0){
+        data.doc.subList=getMixRatioShowDatas(result.subList);
+    }
     let stateList= await changAdjustState(data,rationList);
     mresult.data=data;
     mresult.stateList=stateList;
@@ -665,12 +680,38 @@ async function doRationGLJUpdate(data){
     return resutl;
 }
 
-
+async function getGLJClass(info,data) {
+    let result={
+        exist:false
+    }
+    //检查补充工料机中是否已经存在一样的记录了
+    let condition = {
+        userId:info.userID,
+        compilationId:info.compilationId,
+        code:data.code,
+        name:data.name,
+        unit:data.unit,
+        gljType:data.type,
+        basePrice:data.basePrice
+    }
+    if(data.specs!=null&&data.specs!=undefined&&data.specs!=''){
+        condition['specs']=data.specs;
+    }
+    let glj = await complementaryGljModel.find(condition);
+    if(glj.length>0){ //如果已存在就直接返回,不用再新增了
+        result.exist = true;
+        return result
+    }
+    //查找工料机类型树
+   let items = await gljClassModel.find({"repositoryId": info.gljLibId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]});
+    result.items = items;
+   return result;
+}
 
 async function changAdjustState(data,rationList) {
     let stateList=[];
     for(let r of rationList){
-      let stateResult = await glj_calculate_facade.calculateQuantity({projectID:data.query.projectID,rationID:r});
+      let stateResult = await glj_calculate_facade.calculateQuantity({projectID:data.query.projectID,rationID:r},true);
       stateList.push({rationID:r,adjustState:stateResult.adjustState});
     }
     return stateList;

+ 1 - 0
modules/ration_glj/routes/ration_glj_route.js

@@ -13,6 +13,7 @@ module.exports = function (app) {
     rgRouter.post('/replaceGLJ',rgController.replaceGLJ);
     rgRouter.post('/mReplaceGLJ',rgController.mReplaceGLJ);
     rgRouter.post('/updateRationGLJByEdit',rgController.updateRationGLJByEdit);
+    rgRouter.post('/getGLJClass', rgController.getGLJClass);
     app.use('/rationGlj',rgRouter);
 }
 

+ 3 - 0
public/web/sheet/sheet_common.js

@@ -97,6 +97,9 @@ var sheetCommonObj = {
         //sheet.addRows(row, 1);
 
         sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        if(sheet.getRowCount()<data.length){
+            sheet.setRowCount(data.length);
+        }
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {

+ 16 - 0
public/web/tree_table/tree_table.js

@@ -198,6 +198,17 @@
  			return treenode;
  		};
 
+		Tree.prototype.findNodeByNid = function (nid) {
+			let treenode = null,
+				callback = function (node) {
+					if(node.data && node.data[node.setting.tree.nid] === nid){
+						treenode = node;
+					}
+				};
+			this.traverseDF.call(this, callback);
+			return treenode;
+		}
+
  		Tree.prototype.findNodeByDomId = function (domId) {
  			var treenode = null,
  				callback = function (node) {
@@ -274,6 +285,11 @@
 					parent.children.splice(parent.childIndex(node), 1);
 					parent.children.splice(parent.childIndex(next), 0, node);
 				};
+				let pre = that.findNodeByNid(node.data.ID) || null;
+				if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){
+					parent.children.splice(parent.childIndex(pre), 1);
+					parent.children.splice(parent.childIndex(node), 0, pre);
+				}
 			};
 
  			for (i = 0; i < arrData.length; i++){

+ 51 - 45
web/building_saas/css/main.css

@@ -8,10 +8,10 @@ body {
     font-size: 0.9rem
 }
 .btn.disabled, .btn:disabled {
-  color:#999
+    color:#999
 }
 .btn-link:focus, .btn-link:hover{
-  text-decoration: none
+    text-decoration: none
 }
 /*自定义css*/
 .header {
@@ -28,10 +28,10 @@ body {
     line-height: inherit
 }
 .top-msg{
-  position: fixed;
-  top:0;
-  width:100%;
-  z-index: 999
+    position: fixed;
+    top:0;
+    width:100%;
+    z-index: 999
 }
 .in-1{padding-left:0px!important}
 .in-2{padding-left:21px!important}
@@ -70,7 +70,7 @@ body {
     color: #333
 }
 .main-nav .nav-tabs{
-  border-bottom: none
+    border-bottom: none
 }
 .content {
     border-left: 1px solid #ccc;
@@ -78,7 +78,7 @@ body {
     background: #fff
 }
 .toolsbar,.toolsbar-f {
-  border-bottom: 1px solid #ccc
+    border-bottom: 1px solid #ccc
 }
 .tools-btn {
     height: 30px;
@@ -92,23 +92,23 @@ body {
     overflow-y: hidden;
 }
 .main-data-top,.main-data-full{
-  overflow: hidden;
-  width:100%
+    overflow: hidden;
+    width:100%
 }
 .main-content.col-lg-8{
-  width:66.666667%
+    width:66.666667%
 }
 .main-content.col-lg-12{
-  width:100%
+    width:100%
 }
 .main-side.col-lg-4{
-  width: 33.333333%;
+    width: 33.333333%;
 }
 .main-side.col-lg-0{
-  width:0%;
+    width:0%;
 }
 .sidebar-bottom,.sidebar-bottom .col-lg-6,.sidebar-bottom .col-lg-12 {
-  height:300px
+    height:300px
 }
 .top-content, .fluid-content {
     overflow: auto;
@@ -124,7 +124,7 @@ body {
     padding: 0.2em 0.5em
 }
 .side-tabs .nav-tabs .nav-item {
-  z-index: 999
+    z-index: 999
 }
 .side-tabs .nav-tabs {
     border-bottom: none;
@@ -251,63 +251,69 @@ body {
     overflow: auto;
 }
 .poj-list span.poj-icon {
-  padding-right:7px;
-  color:#ccc
+    padding-right:7px;
+    color:#ccc
 }
 .poj-list a.tree-open,.poj-list a.tree-close{
-  width:15px;
-  display: inline-block;
+    width:15px;
+    display: inline-block;
 }
 .print-toolsbar{
-  padding:5px
+    padding:5px
 }
 .print-toolsbar .panel {
-  display:inline-block;
-  vertical-align:top;
-  background:#f7f7f9
+    display:inline-block;
+    vertical-align:top;
+    background:#f7f7f9
 }
 .print-toolsbar .panel .panel-foot{
-  text-align: center;
-  font-size: 12px
+    text-align: center;
+    font-size: 12px
 }
 .print-list {
-  border-right:1px solid #ccc
+    border-right:1px solid #ccc
 }
 .print-list .form-list {
-  overflow: auto
+    overflow: auto
 }
 .print-list .list-tools{
-  height:50px;
-  padding:10px 0;
-  border-bottom:1px solid #f2f2f2
+    height:50px;
+    padding:10px 0;
+    border-bottom:1px solid #f2f2f2
 }
 .pageContainer {
-  background: #ededed;
-  text-align: center
+    background: #ededed;
+    text-align: center
 }
 .pageContainer .page{
-  border:9px solid transparent;
-  display: inline-block;
+    border:9px solid transparent;
+    display: inline-block;
 }
 .pageContainer .page img{
-  width:inherit;
-  height: inherit;
+    width:inherit;
+    height: inherit;
 }
 .modal-auto-height {
-  height: 400px;
-  overflow-y: auto;
+    height: 400px;
+    overflow-y: auto;
 }
 .modal-fixed-height {
-  height: 400px;
-  overflow-y: hidden;
+    height: 400px;
+    overflow-y: hidden;
 }
 .sidebar-tools-bar {
-  background:#fff
+    background:#fff
 }
 .side-search-box{
-  background:#fff;
-  border-bottom:1px solid #ddd
+    background:#fff;
+    border-bottom:1px solid #ddd
 }
 .navbar-crumb span{
-  max-width: 200px
+    max-width: 200px
+}
+.dropdown-item{
+    color:#007bff
+}
+.dropdown-item.disabled, .dropdown-item:disabled{
+    pointer-events:none
 }

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

@@ -133,7 +133,6 @@ CompositionSpread.prototype.getRatioData = function(projectGLJid) {
         success: function(response) {
             if (response.err === 0) {
                 response.data = JSON.parse(response.data);
-                console.log(response.data);
                 // 设置数据
                 self.sheetObj.setData(response.data);
                 self.specialColumn(response.data);

+ 11 - 0
web/building_saas/glj/js/project_glj.js

@@ -179,6 +179,17 @@ $(document).ready(function () {
                     alert(msg);
                     return false;
                 }
+                projectObj.project.projectGLJ.loadData(function () {
+                    let projectGLJ = projectObj.project.projectGLJ;
+                    let data = projectGLJ.datas;
+                    projectGLJ.loadCacheData();
+                    let usedTenderList = data.usedTenderList !== undefined ? data.usedTenderList : [];
+                    let  usedUnitPriceInfo = data.constData.usedUnitPriceInfo !== undefined ?
+                        data.constData.usedUnitPriceInfo : {};
+
+                    unitPriceFileInit(usedUnitPriceInfo.name, usedTenderList);
+
+                });
                 $('#change-dj').modal("hide");
             }
         });

+ 38 - 8
web/building_saas/main/html/main.html

@@ -264,7 +264,7 @@
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-2" role="tab">工程特征</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-3" role="tab">指标信息</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-4" role="tab">关于计算</a></li>
-                                <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-billsQuanDecimal" id="tab_poj-settings-bqDecimal" role="tab">清单工程精度</a></li>
+                                <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-billsQuanDecimal" id="tab_poj-settings-bqDecimal" role="tab">清单工程精度</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-decimal" role="tab" id="tab_poj-settings-decimal">小数位数</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-6" role="tab" id="tab_poj-settings-6">人工单价调整</a></li>
                             </ul>
@@ -385,7 +385,7 @@
                                             <div class="row m-0">
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">工程量</div>
+                                                        <div class="input-group-addon">消耗量</div>
                                                         <input type="number" name="glj-quantity" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
@@ -553,6 +553,37 @@
             </div>
         </div>
     </div>
+    <!--工料机类型选择-->
+    <div class="modal fade" id="glj_class_div" data-backdrop="static">
+        <div class="modal-dialog modal-m" role="document" id="class_con">
+            <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>
+                    <input type="hidden" name="" id="selected_class">
+                </div>
+                <div class="modal-body">
+                    <div class="row">
+                        <div class="col-12">
+                            <div  class="modal-auto-height" id="classTreeDiv" style="overflow: hidden">
+                                <!--<div class="print-list">-->
+                                <div style="width: 100%; height: 100%; overflow: auto">
+                                    <ul id="classTree" class="ztree"></ul>
+                                </div>
+                                <!--</div>-->
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" id="classCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <button type="button" href="javascript:void(0);" id="class_selected_conf" class="btn btn-primary" disabled >确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!--费率选择窗口-->
     <div class="modal fade" id="fee_rate_tree" data-backdrop="static">
         <div class="modal-dialog modal-feeRate" role="document" id="fee_rate_dialog">
@@ -566,17 +597,16 @@
                 <div class="modal-body">
                     <input type="hidden" id="edit_from">
                     <div class="row">
-                        <div class="modal-auto-height col-12" style="overflow: hidden" id="fee_rate_sheet">
+                        <div class="modal-auto-height col-12" style="overflow: hidden" id="fee_rate_sheet"></div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" id="frCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript:void(0);" id="fee_selected_conf" class="btn btn-primary">确定</a>
                     </div>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" id="frCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="javascript:void(0);" id="fee_selected_conf" class="btn btn-primary">确定</a>
                 </div>
             </div>
         </div>
     </div>
-
         <!-- JS. -->
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
 

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

@@ -182,6 +182,7 @@ var Bills = {
                     data.data.itemCharacter = stdBillsData.itemCharacter;
                     data.data.jobContentText = stdBillsData.jobContentText;
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
+                    data.data.programID = stdBillsData.engineering;
                     //zhong
                     newData = data.data;
                 }
@@ -332,6 +333,7 @@ var Bills = {
                 // 特征
                 node.data.itemCharacter = stdBillsData.itemCharacter;
                 node.data.itemCharacterText = stdBillsData.itemCharacterText;
+                node.data.programID = stdBillsData.engineering;
             }
             updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(node.data)});
 

+ 83 - 35
web/building_saas/main/js/models/calc_program.js

@@ -290,21 +290,24 @@ let executeObj = {
                     }
                 };
             }else{
-                for (let glj of me.treeNode.data.gljList) {
-                    if (base.gljTypes.indexOf(glj.type) >= 0) {
-                        if (base.calcType == baseCalc){ price = glj["basePrice"];}
-                        else if (base.calcType == adjustCalc){price = glj["adjustPrice"];}
-                        else if (base.calcType == budgetCalc){price = glj["marketPrice"];}
-                        else if (base.calcType == diffCalc){
-                            aprice = glj["adjustPrice"];
-                            if (!aprice) aprice = 0;
-                            mprice = glj["marketPrice"];
-                            if (!mprice) mprice = 0;
-                            price = mprice - aprice;
+                if (!me.treeNode.data.gljList) tmpSum = 0
+                else{
+                    for (let glj of me.treeNode.data.gljList) {
+                        if (base.gljTypes.indexOf(glj.type) >= 0) {
+                            if (base.calcType == baseCalc){ price = glj["basePrice"];}
+                            else if (base.calcType == adjustCalc){price = glj["adjustPrice"];}
+                            else if (base.calcType == budgetCalc){price = glj["marketPrice"];}
+                            else if (base.calcType == diffCalc){
+                                aprice = glj["adjustPrice"];
+                                if (!aprice) aprice = 0;
+                                mprice = glj["marketPrice"];
+                                if (!mprice) mprice = 0;
+                                price = mprice - aprice;
+                            };
+                            if (!price) price = 0;
+                            tmpSum = tmpSum + (glj["quantity"] * price).toDecimal(me.digitDefault);
+                            tmpSum = (tmpSum).toDecimal(me.digitDefault);
                         };
-                        if (!price) price = 0;
-                        tmpSum = tmpSum + (glj["quantity"] * price).toDecimal(me.digitDefault);
-                        tmpSum = (tmpSum).toDecimal(me.digitDefault);
                     };
                 };
             };
@@ -351,7 +354,9 @@ class CalcProgram {
         me.compiledFeeRates = {};
         me.compiledLabourCoes = {};
         me.compiledTemplates = {};
-        me.compiledFeeTypes = {};
+        me.compiledTemplateMaps = {};
+        me.compiledTemplateNames = [];
+        me.compiledFeeTypeMaps = {};
         me.compiledFeeTypeNames = [];
         me.compiledCalcBases = {};
         me.saveForReports = [];
@@ -391,8 +396,8 @@ class CalcProgram {
         }
 
         for (let ft of me.feeTypes) {
-            me.compiledFeeTypes[ft.type] = ft.name;
-            me.compiledFeeTypes[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
+            me.compiledFeeTypeMaps[ft.type] = ft.name;
+            me.compiledFeeTypeMaps[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
             me.compiledFeeTypeNames.push(ft.name);
         }
 
@@ -404,6 +409,9 @@ class CalcProgram {
     compileTemplate(template){
         let me = this;
         me.compiledTemplates[template.ID] = template;
+        me.compiledTemplateMaps[template.ID] = template.name;
+        me.compiledTemplateMaps[template.name] = template.ID;
+        me.compiledTemplateNames.push(template.name);
         template.hasCompiled = false;
         template.errs = [];
 
@@ -487,7 +495,7 @@ class CalcProgram {
                 };
 
                 // 字段名映射
-                item.displayFieldName = me.compiledFeeTypes[item.fieldName];
+                item.displayFieldName = me.compiledFeeTypeMaps[item.fieldName];
             }
         };
 
@@ -513,7 +521,7 @@ class CalcProgram {
         };
     };
 
-    // 内部调用,外部不能直接使用
+    // 仅内部调用。注意:外部不能直接使用
     InnerCalc(treeNode){
         let me = this;
         let project = me.project;
@@ -686,29 +694,69 @@ class CalcProgram {
     saveNode(treeNode, saveParents = true) {
         if (!treeNode.changed) return;
         let me = this;
-        let newDataArr = [], nodesArr = [];
-
-        me.project.beginUpdate('');
+        let nodesArr = [];
         let curNode = treeNode;
         while (curNode) {
-            if (curNode.changed){
+            if (curNode.changed){nodesArr.push(curNode)};
+            if (saveParents) curNode = curNode.parent
+            else break;
+        };
+        me.saveNodes(nodesArr);
+    };
+
+    // 多个树结点入库存储,刷新界面显示。
+    saveNodes(treeNodes){
+        if (treeNodes.length < 1) return;
+
+        let me = this;
+
+        me.project.beginUpdate('');
+        for (let node of treeNodes){
+            if (node.changed){
                 let data = {
-                    ID: curNode.data.ID,
+                    ID: node.data.ID,
                     projectID: me.project.ID(),
-                    quantity: curNode.data.quantity,
-                    fees: curNode.data.fees
+                    quantity: node.data.quantity,
+                    programID: node.data.programID,
+                    fees: node.data.fees
                 };
-                let newDta = {'updateType': 'ut_update', 'updateData': data};
-                newDataArr.push(newDta);
-                nodesArr.push(curNode);
-                me.project.push(curNode.sourceType, newDataArr);
-            };
-            if (saveParents) curNode = curNode.parent
-            else break;
+                let newData = {'updateType': 'ut_update', 'updateData': data};
+                me.project.push(node.sourceType, [newData]);
+            }
         };
         me.project.endUpdate();
 
-        for (let node of nodesArr){delete node.changed;};
-        projectObj.mainController.refreshTreeNode(nodesArr);
+        for (let node of treeNodes){delete node.changed};
+        projectObj.mainController.refreshTreeNode(treeNodes);
+
+        if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+            calcProgramObj.showData(me.project.mainTree.selected, false);
+        };
+    };
+
+/*    计算所有树结点(分3种情况),并将发生计算改动的结点入库存储。
+    参数取值如下:
+    calcAllType.catAll       计算所有树结点 (不指定参数时的默认值)
+    calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
+    calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到) */
+    calcAllNodes(calcType = calcAllType.catAll){
+        let me = this;
+        let needSaveNodes = [];
+
+        function calcNodes(nodes) {
+            for (let node of nodes) {
+                if (node.children.length > 0) {
+                    calcNodes(node.children);
+                };
+
+                if ((calcType == calcAllType.catAll) || (calcType == node.sourceType)) {
+                    me.calculate(node, false);
+                    if (node.changed) needSaveNodes.push(node);
+                };
+            }
+        };
+
+        calcNodes(me.project.mainTree.roots);
+        me.saveNodes(needSaveNodes);
     };
 }

+ 18 - 2
web/building_saas/main/js/models/main_consts.js

@@ -36,10 +36,26 @@ const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
     totalFee: 90
 };
 
-treeNodeCalcType = {
+const treeNodeCalcType = {
     ctRationCalcProgram: 1,
     ctBillCalcProgram: 2,
     ctGatherRations: 3,
     ctGatherBills: 4,
     ctCalcBaseValue: 5
-};
+};
+
+const calcAllType = {
+    catAll: 'all',
+    catBills: 'bills',
+    catRations: 'ration'
+};
+
+const subSheetIndex = {
+    ssiRationGLJ: 0,
+    ssiRationCoe: 1,
+    ssiRationAssistant: 2,
+    ssiQuantityDetail: 3,
+    ssiCalcProgram: 4,
+    ssiMemo: 5,
+    ssiFeature: 6
+}

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

@@ -373,13 +373,6 @@ var Ration = {
 
             this.project.endUpdate();
         };
-
-        ration.prototype.calcAll = function (){
-            for (let ration of this.datas){
-                let node = this.project.mainTree.findNode(ration.ID);
-                 this.project.calcProgram.calculate(node);
-            };
-        };
         
         return new ration(project);
     }

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

@@ -41,9 +41,11 @@ var ration_glj = {
         };
 
         ration_glj.prototype.getGljArrByRation = function (rationID) {
-            return this.datas.filter(function (data) {
+            let result =  this.datas.filter(function (data) {
                 return data.rationID === rationID;
             })
+            result = gljOprObj.combineWithProjectGlj(result);
+            return result;
         };
         ration_glj.prototype.getGatherGljArrByRations = function (rations) {
             let result = [];
@@ -98,8 +100,9 @@ var ration_glj = {
         ration_glj.prototype.refreshAfterSave=function(data){
             let neRecodes=[];
             if(data){
-                neRecodes=data.newRecords;
-                gljOprObj.sheetData=data.showDatas;
+               // neRecodes=data.newRecords;//原来是显示和缓存分开的,后来发现会导致数据不一致的问题所以改成统一的了,这里也只是会作为显示。
+                neRecodes = data.showDatas;
+                gljOprObj.sheetData=neRecodes;
             }
             if(projectObj.project.ration_glj.datas&&Array.isArray(projectObj.project.ration_glj.datas)){
                 if(data){
@@ -109,6 +112,12 @@ var ration_glj = {
                 projectObj.project.ration_glj.datas = neRecodes;
             }
             gljOprObj.showRationGLJSheetData(true);
+            let node = project.mainTree.selected;
+            project.calcProgram.calculate(node);
+            project.calcProgram.saveNode(node);
+            if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+                calcProgramObj.showData(node, false);
+            };
         };
         ration_glj.prototype.refreshAfterUpdate=function(data){
             var me = this;
@@ -131,7 +140,6 @@ var ration_glj = {
             })
             _.forEach(doc, function(n, key) {
                 glj_list[glj_index][key] = n;
-                gljOprObj.sheetData[sheet_index][key]=n;
             });
             return glj_list[glj_index].rationID;
         };
@@ -181,7 +189,7 @@ var ration_glj = {
                 for(let i=0;i<data.rationGljList.length;i++){
                     let temdata = data.rationGljList[i];
                     let newGLJ = {};
-                    newGLJ.projectID = newRation.projectID;
+                    newGLJ.projectID = parseInt(newRation.projectID);
                     newGLJ.GLJID = temdata.gljId;
                     newGLJ.rationID = newRation.ID;
                     newGLJ.billsItemID=newRation.billsItemID,
@@ -274,6 +282,7 @@ var ration_glj = {
             var me=this;
             $.bootstrapLoading.start();
             var callback=function (data) {
+                let initShow = false;//是否需要表格初始化显示
                 if(updateField=='customQuantity'){
                     me.refreshAfterQuantityUpdate(data);
                 }else {
@@ -284,9 +293,17 @@ var ration_glj = {
                     if(data.hasOwnProperty('adjustState')){//更新定额调整状态
                         me.updateRationAdjustState(data.adjustState);
                     }
+                    if(recode.subList&&recode.subList.length>0){
+                        initShow = true;
+                    }
+                }
+                if(initShow==false){//不需要初始化,只需耍新当前显示就可以了
+                    gljOprObj.showRationGLJSheetData();
                 }
-                gljOprObj.showRationGLJSheetData();
                 projectObj.project.projectGLJ.loadData(function () {//等项目工料机加载完成后再给用户编辑
+                    if(initShow==true){
+                        gljOprObj.refreshView();
+                    }
                     $.bootstrapLoading.end();
                 });
             }
@@ -337,6 +354,7 @@ var ration_glj = {
                   quantity:0,
                   name:glj.name,
                   code:glj.code,
+                  original_code:glj.code,
                   unit:glj.unit,
                   specs:glj.specs,
                   basePrice:glj.basePrice,
@@ -347,10 +365,17 @@ var ration_glj = {
               }
               if(glj.hasOwnProperty("compilationId")){
                   ration_glj.from="cpt";
+                  if(glj.code.indexOf('-')!=-1){//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
+                      ration_glj.original_code = glj.code.split('-')[0];//取-前的编号作为原始编号
+                  }
               }
+
               gljList.push(ration_glj);
           });
-            CommonAjax.post("/rationGlj/addGLJ",gljList,callback);
+          $.bootstrapLoading.start();
+            CommonAjax.post("/rationGlj/addGLJ",gljList,callback,function () {
+                $.bootstrapLoading.end();
+            });
         };
         ration_glj.prototype.replaceGLJ=function (selectCode,oldData,callback) {
             var allGLJ=gljOprObj.AllRecode;
@@ -366,16 +391,23 @@ var ration_glj = {
             oldData.rationItemQuantity=0;
             oldData.name=glj.name;
             oldData.code=glj.code;
+            oldData.original_code=glj.code;
             oldData.unit=glj.unit;
             oldData.specs=glj.specs;
             oldData.basePrice=glj.basePrice;
             oldData.repositoryId=glj.repositoryId;
             if(glj.hasOwnProperty("compilationId")){
                 oldData.from="cpt";
+                if(glj.code.indexOf('-')!=-1){//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
+                    oldData.original_code = glj.code.split('-')[0];//取-前的编号作为原始编号
+                }
             }else {
                 oldData.from="std";
             }
-            CommonAjax.post("/rationGlj/replaceGLJ",oldData,callback);
+            $.bootstrapLoading.start();
+            CommonAjax.post("/rationGlj/replaceGLJ",oldData,callback,function () {
+                $.bootstrapLoading.end();
+            });
         };
 
         ration_glj.prototype.mReplaceGLJ=function (selectCode,oldData,callback) {
@@ -387,7 +419,12 @@ var ration_glj = {
             var query={
                 projectID:oldData.projectID,
                 code:oldData.code,
-                name:oldData.name
+                name:oldData.name,
+                unit:oldData.unit,
+                type:oldData.type
+            }
+            if(oldData.specs&&oldData.specs!=''){
+                query.specs=oldData.specs;
             }
             var doc={
                 GLJID:glj.ID,
@@ -395,6 +432,7 @@ var ration_glj = {
                 rationItemQuantity:0,
                 name:glj.name,
                 code:glj.code,
+                original_code:glj.code,
                 unit:glj.unit,
                 specs:glj.specs,
                 type:glj.gljType,
@@ -409,12 +447,16 @@ var ration_glj = {
             }
             if(glj.hasOwnProperty("compilationId")){
                 doc.from="cpt";
+                if(glj.code.indexOf('-')!=-1){//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
+                    doc.original_code = glj.code.split('-')[0];//取-前的编号作为原始编号
+                }
             }else {
                 doc.from="std";
             }
-            CommonAjax.post("/rationGlj/mReplaceGLJ",{query:query,doc:doc},callback);
-
-
+            $.bootstrapLoading.start();
+            CommonAjax.post("/rationGlj/mReplaceGLJ",{query:query,doc:doc},callback,function () {
+                $.bootstrapLoading.end();
+            });
         };
         return new ration_glj(project);
     }

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

@@ -33,7 +33,7 @@ let rationPM = {
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1,2,4,5,6],
+            lockColumns:[0,1,2,5,6],
             colHeaderHeight: CP_Col_Width.colHeader,
             rowHeaderWidth: CP_Col_Width.rowHeader
         }

+ 5 - 3
web/building_saas/main/js/views/calc_program_view.js

@@ -225,11 +225,13 @@ let calcProgramObj = {
         sheetCommonObj.initSheet(me.sheet, me.setting, 1);
     },
 
-    showData: function (treeNode) {
+    showData: function (treeNode, needCalc = true) {
         var me = this;
         me.treeNode = treeNode;
-        projectObj.project.calcProgram.calculate(treeNode);
-        projectObj.project.calcProgram.saveNode(treeNode);
+        if (needCalc){
+            projectObj.project.calcProgram.calculate(treeNode);
+            projectObj.project.calcProgram.saveNode(treeNode);
+        };
         me.datas = treeNode.data.calcTemplate.calcItems;
         sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
         sheetCommonObj.showData(me.sheet, me.setting, me.datas);

+ 124 - 29
web/building_saas/main/js/views/glj_view.js

@@ -15,6 +15,7 @@ var gljOprObj = {
     detailSheet:null,
     detailData:[],
     GLJSelection:[],
+    selectedGLJClass:null,
     parentNodeIds:{},
     activeTab:'#linkGLJ',
     decimalSetting:{
@@ -107,12 +108,23 @@ var gljOprObj = {
         },
         callback:{
             onClick: function(event,treeId,treeNode) {
-                let me = gljOprObj, gljTypeId = treeNode.ID;
-                if(me.gljCurTypeId !== treeNode.ID){
-                    me.gljCurTypeId = treeNode.ID;
-                    me.filterLibGLJSheetData();
-                    me.showLibGLJSheetData();
+                if(treeId=='gljTree'){
+                    let me = gljOprObj, gljTypeId = treeNode.ID;
+                    if(me.gljCurTypeId !== treeNode.ID){
+                        me.gljCurTypeId = treeNode.ID;
+                        me.filterLibGLJSheetData();
+                        me.showLibGLJSheetData();
+                    }
+                }else {
+                    if(treeNode.isParent){
+                        $('#class_selected_conf').attr("disabled","disabled");
+                        $('#selected_class').val("");
+                    }else {
+                        $('#class_selected_conf').removeAttr("disabled");
+                        $('#selected_class').val(treeNode.ID);
+                    }
                 }
+
             }
         }
     },
@@ -418,6 +430,11 @@ var gljOprObj = {
         var me = gljOprObj;
         var header = me.setting.header;
         var disable = null;
+        if(me.sheetData[args.row]!=undefined){
+            if(me.sheetData[args.row].isMixRatio){
+                disable = true;
+            }
+        }
         if(header[args.col]&&header[args.col].dataCode=='marketPrice'){
             var type = me.sheetData[args.row].shortName;
             var index= _.indexOf(me.setting.notEditedType,type);
@@ -534,22 +551,25 @@ var gljOprObj = {
         }
     },
     showRationGLJSheetData:function (init) {
-        if(init){
-            this.sheet.getRange(0,-1,this.sheet.getRowCount(),-1).visible(true);
-            this.sheetData=_.sortBy(this.sheetData,'type');
-            this.addMixRatioToShow();
-            this.initRationTree();
-        }
+        this.sheet.getRange(0,-1,this.sheet.getRowCount(),-1).visible(true);
+        this.sheetData=_.sortBy(this.sheetData,'type');
+        this.addMixRatioToShow();
+        this.initRationTree(init);
         sheetCommonObj.showData(this.sheet,this.setting,this.sheetData);
 
     },
-    initRationTree:function () {
+    initRationTree:function (init) {
         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')){
-                this.sheet.setTag(i,0,true);
-                this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).visible(false);
-                this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).locked(true);
+                var collapsed = false;
+                if(init){
+                    this.sheetData[i].collapsed=true;
+                    collapsed = true;
+                }else {
+                    collapsed = this.sheetData[i].collapsed==undefined?true:this.sheetData[i].collapsed;
+                }
+                this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).visible(!collapsed);// this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).locked(true);
             }
         }
     },
@@ -626,7 +646,8 @@ var gljOprObj = {
                 adjustPrice:pg.adjust_price,
                 isEstimate:pg.is_evaluate,
                 isMixRatio:true,
-                isAdd:pg.unit_price.is_add
+                isAdd:pg.unit_price.is_add,
+                GLJID:pg.glj_id
             }
             temRationGLJs.push(tem);
         }
@@ -696,10 +717,14 @@ var gljOprObj = {
         var recode = me.sheetData[args.row];
         var newval;
         if(updateField=='marketPrice'||updateField=='customQuantity'||updateField=='basePrice'){
-            newval = number_util.checkNumberValue(args.editingText,this.decimalSetting[updateField]);
-            if(!newval){
-                me.sheet.getCell(args.row, args.col).value(recode[updateField]);
-                return;
+            if(args.editingText==null){
+                newval="";
+            }else {
+                newval = number_util.checkNumberValue(args.editingText,this.decimalSetting[updateField]);
+                if(newval==null){
+                    me.sheet.getCell(args.row, args.col).value(recode[updateField]);
+                    return;
+                }
             }
         }else {
              if(updateField=='name'||updateField=='unit'){
@@ -711,6 +736,9 @@ var gljOprObj = {
              }
             newval=args.editingText==null?"":args.editingText;
         }
+        if(newval === recode[updateField]){//如果值完全相等,则不需要更新
+            return
+        }
         if(updateField=='marketPrice'||updateField=='basePrice'){
             projectObj.project.projectGLJ.updatePriceFromRG(recode,updateField,newval);
         } else {
@@ -886,15 +914,17 @@ var gljOprObj = {
             return _.find(gljOprObj.sheetData,{'code':n})?false:true;
         })
         if(gljOprObj.GLJSelection.length>0&&selected&&selected.sourceType==ModuleNames.ration){
+            $("#glj_tree_div").modal('hide');
             project.ration_glj.addGLJByLib(gljOprObj.GLJSelection,selected.data,function (result) {
                 if(result){
                     selected.data.adjustState=result.adjustState;
-                    project.ration_glj.datas = project.ration_glj.datas.concat(result.newRecodes);
+                    //project.ration_glj.datas = project.ration_glj.datas.concat(result.newRecodes);//显示和缓存统一,这样的话就不用更新两个位置了
+                    project.ration_glj.datas = project.ration_glj.datas.concat(result.showData);
                     gljOprObj.sheetData = gljOprObj.sheetData.concat(result.showData)
                     gljOprObj.showRationGLJSheetData();
                     project.projectGLJ.loadData();
                     projectObj.mainController.refreshTreeNode([selected]);
-                    $("#glj_tree_div").modal('hide');
+                    $.bootstrapLoading.end();
                 }
             });//doc.rationID=selected.data.ID;
         }else {
@@ -908,6 +938,7 @@ var gljOprObj = {
         var project= projectObj.project;
         var selectCode=gljOprObj.GLJSelection[0];
         var selected = projectObj.project.mainTree.selected;
+        $("#glj_tree_div").modal('hide');
         project.ration_glj.replaceGLJ(selectCode,oldData,function (result) {
             if(result){
                 //result.adjustState;
@@ -919,7 +950,7 @@ var gljOprObj = {
                 selected.data.adjustState=result.adjustState;
                 projectObj.mainController.refreshTreeNode([selected]);
             }
-            $("#glj_tree_div").modal('hide');
+            $.bootstrapLoading.end();
         })
     },
     doMReplaceGLJ:function () {
@@ -927,18 +958,21 @@ var gljOprObj = {
         var oldData=me.sheetData[gljContextMenu.selectedRow];
         var project= projectObj.project;
         var selectCode=me.GLJSelection[0];
+        $("#glj_tree_div").modal('hide');
         project.ration_glj.mReplaceGLJ(selectCode,oldData,function (result) {
             var data=result.data;
             var stateList= result.stateList;
+            var n_index = me.getIndex(data.query,['code','name','specs','unit','type']);
             _.forEach(project.ration_glj.datas,function (t) {
-                if(t.code==data.query.code&&t.name==data.query.name){
+                var t_index =me.getIndex(t,['code','name','specs','unit','type']);
+                if(n_index==t_index){
                     me.updateProperty(t,data.doc);
                 }
             })
             me.showRationGLJSheetData();
             project.projectGLJ.loadData();
             me.refreshStateAfterMreplace(stateList);
-            $("#glj_tree_div").modal('hide');
+            $.bootstrapLoading.end();
         })
     },
     updateProperty:function (obj,doc) {
@@ -1030,7 +1064,7 @@ var gljOprObj = {
                 var recode = data[options.row];
                 if(recode&&recode.hasOwnProperty('subList')){
                     drowRect(ctx,x,y,w,h);
-                    var collapsed = options.sheet.getTag(options.row,options.col);
+                    var collapsed = recode.collapsed==undefined?true:recode.collapsed;//options.sheet.getTag(options.row,options.col);
                     drowSymbol(ctx,x,y,w,h,collapsed);
                 }else if(recode&&recode.isMixRatio){
                     offset= drowSubItem(ctx,x,y,w,h,offset,data[options.row+1]);
@@ -1056,9 +1090,10 @@ var gljOprObj = {
             if(recode&&recode.hasOwnProperty('subList')){
                var hoffset= hitinfo.cellRect.x+3;
                 if (hitinfo.x > hoffset && hitinfo.x < hoffset + 10){
-                    var collapsed =  hitinfo.sheet.getTag(hitinfo.row,hitinfo.col,hitinfo.sheetArea);
-                    collapsed = !collapsed;
-                    hitinfo.sheet.setTag(hitinfo.row,hitinfo.col,collapsed);
+                    var collapsed = recode.collapsed==undefined?true:recode.collapsed;
+                    collapsed = !collapsed
+                    recode.collapsed=collapsed;
+                    //hitinfo.sheet.setTag(hitinfo.row,hitinfo.col,collapsed);
                     hitinfo.sheet.getRange(hitinfo.row+1, -1, recode.subList.length, -1).visible(!collapsed);
                     hitinfo.sheet.invalidateLayout();
                     hitinfo.sheet.repaint();
@@ -1119,6 +1154,66 @@ $(function(){
             gljOprObj.doMReplaceGLJ();
         }
     })
+
+    $('#class_selected_conf').click(function () {
+        var gljClass =  $('#selected_class').val();
+        var glj = gljOprObj.selectedGLJClass;
+        if(glj&&gljClass&&gljClass!=""){
+            //保存到我的工料机库
+            /*1 检查是否有组成物
+            * 2 如果有,则检查组成物中是否有新增的记录,如果有,查看是否已经保存了,没有的话,要先添加组成物到补充工料机库
+            * 3 保存
+
+            * */
+            var newItem={
+                code:glj.code,
+                name:glj.name,
+                specs:glj.specs,
+                unit:glj.unit,
+                basePrice:glj.basePrice,
+                gljType:glj.type,
+                shortName:glj.shortName,
+                component:[],
+                gljClass:gljClass
+            };
+            if(glj.hasOwnProperty("subList")&&glj.subList.length>0){//有组成物,检查组成物信息,目前组成物不允许修改,所以暂时不用考虑组成物是新增的情况
+                for(var i=0;i<glj.subList.length;i++ ){
+                    let tem={
+                        ID:glj.subList[i].GLJID,
+                        consumeAmt:glj.rationItemQuantity,
+                        isStd:true
+                    }
+                    newItem.component.push(tem);
+                }
+            }
+            var data = getcmpUpdateData([newItem]);
+            $.bootstrapLoading.start();
+            var callback = function (data) {
+                $("#glj_class_div").modal('hide');
+                $.bootstrapLoading.end();
+            }
+            CommonAjax.post("complementartGlj/api/mixUpdateGljItems", data, callback, function () {
+                $.bootstrapLoading.end();
+            });
+        }
+    })
+
+    $('#glj_class_div').on('hidden.bs.modal', function (e){
+        gljOprObj.selectedGLJClass=null;
+        $('#class_selected_conf').attr("disabled","disabled");
+        $('#selected_class').val("");
+    })
+
+    function getcmpUpdateData(items) {
+        var data ={
+            "updateItems": [],
+            "removeIds": []
+        }
+        data.addItems = items;
+        return data;
+    }
+
+
 })
 
 

+ 15 - 1
web/building_saas/main/js/views/glj_view_contextMenu.js

@@ -90,7 +90,9 @@ var gljContextMenu = {
                         return disable;
                     },
                     callback: function () {
-                        getGLJData('m_replace');
+                        var sheetData = gljOprObj.sheetData;
+                        var recode = sheetData[gljContextMenu.selectedRow];
+                        showGLJClassTree(recode);
                     }
                 }
             }
@@ -205,4 +207,16 @@ function getGLJData(actionType) {
         $("input[name='glj']").get(0).checked=true;
         $("#glj_tree_div").modal({show:true});
     })
+}
+
+function showGLJClassTree(record) {
+    CommonAjax.post('/rationGlj/getGLJClass',record, function (data) {
+        if(data.exist==true){
+            alert("当前工料机已存在。");
+        }else {
+            gljOprObj.selectedGLJClass = record;
+            $("#glj_class_div").modal({show:true});
+            zTreeHelper.createTree(data.items, gljOprObj.gljTreeSetting, "classTree", gljOprObj);
+        }
+    })
 }

+ 12 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -14,6 +14,12 @@ let MainTreeCol = {
             } else if (node.sourceType === projectObj.project.ration_glj.getSourceType()) {
                 return '主';
             }
+        },
+
+        calcProgramName: function (node) {
+            let programID = node.data.programID;
+            if (!programID) return
+            else return projectObj.project.calcProgram.compiledTemplateMaps[programID];
         }
     },
     readOnly: {
@@ -69,6 +75,12 @@ let MainTreeCol = {
 
         feeRate: function () {
             return feeRateObject.getFeeRateEditCellType();
+        },
+
+        calcProgramName: function () {
+            var names = new GC.Spread.Sheets.CellTypes.ComboBox();
+            names.items(projectObj.project.calcProgram.compiledTemplateNames);
+            return names;
         }
      },
     getEvent: function (eventName) {

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

@@ -28,7 +28,7 @@ var projectInfoObj = {
                 that.projectInfo = data;
                 //init decimal
                 setDecimal(decimalObj, data.property.decimal);
-                billsQuanDecimal.datas = data.property.billsQuantityDecimal;
+                billsQuanDecimal.datas = data.property.billsQuantityDecimal || [billsDecimalView.angleDecimal];
                 $('#fullpath').html(that.getFullPathHtml(that.projectInfo));
             }
         });

+ 7 - 7
web/building_saas/main/js/views/project_property_decimal_view.js

@@ -5,7 +5,7 @@
 let defaultDecimal = {
     min: 0,
     max: 6,
-    _def: {//定义往这加, editable: 开放给用户编辑的(入库),定义editable为false的字段时,只需在此定义便可,定义editable为true的字段时,要在后端project_model.js defaultDecimal中添加定义,html添加input
+    _def: {//editable: 开放给用户编辑的
         bills: {editable: true, data: {unitPrice: 2, totalPrice: 2}},
         ration: {editable: true, data: {quantity: 3, unitPrice: 2, totalPrice: 2}},
         glj: {editable: true, data: {quantity: 3, unitPrice: 2}},
@@ -70,14 +70,9 @@ function toUpdateDecimal(orgV, newV){
 
 function setDecimal(_digits, data){
     if(isDef(data)){
-        for(let attr in data){//设置入库的数据
+        for(let attr in data){
             _digits[attr] = data[attr] || defaultDecimal['_def'][attr]['data'];
         }
-        for(let attr in defaultDecimal['_def']){//设置不入库的数据
-            if(!defaultDecimal['_def'][attr]['editable']){
-                _digits[attr] = defaultDecimal['_def'][attr]['data'];
-            }
-        }
     }
     else {
         for(let attr in defaultDecimal['_def']){
@@ -114,6 +109,11 @@ function m_getDecimalData(inputs){
             rst[attrs[0]] = parseInt($(inputs[i]).val());
         }
     }
+    for(let attr in defaultDecimal['_def']){
+        if(!defaultDecimal['_def'][attr]['editable']){
+            rst[attr] = defaultDecimal['_def'][attr]['data'];
+        }
+    }
     return rst;
 }
 

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

@@ -18,7 +18,7 @@ var projectObj = {
         gljOprObj.showDataIfRationSelect(node);
 
         // CSL.2017.07.25
-        if (SubActiveSheetNameIs('JSCX')) {
+        if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
             if (node.sourceType === project.Bills.getSourceType() || node.sourceType === project.Ration.getSourceType()) {
                 calcProgramObj.showData(node);
             } else {
@@ -125,7 +125,11 @@ var projectObj = {
     checkSpreadEditingText: function (editingText, colSetting) {
         if (colSetting.data.field === 'quantity' || colSetting.data.field === 'feesIndex.common.unitFee') {
             return this.checkFormulaValidField(editingText, colSetting);
-        } else {
+        }
+        else if (colSetting.data.field === 'programID') {
+            return this.project.calcProgram.compiledTemplateMaps[editingText];
+        }
+        else {
             return this.checkCommonField(editingText, colSetting);
         }
     },
@@ -247,9 +251,15 @@ var projectObj = {
     updateCode: function (node, value) {
         let project = projectObj.project;
         if (node.sourceType === project.Bills.getSourceType()) {
-            this.updateBillsCode(node, value);
+            this.updateBillsCode(node, value);   // 新清单不适合实时计算,下面套什么还不能确定,无数量计算也无意义
         } else if (node.sourceType === project.Ration.getSourceType()) {
-            this.updateRationCode(node, value);
+            this.updateRationCode(node, value);  // 新套定额适合实时计算
+            // 这里因异步问题暂时缺少工料机价格。该过程移到:ration_glj.js的refreshAfterSave方法中。
+            /*project.calcProgram.calculate(node);
+            project.calcProgram.saveNode(node);
+            if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+                calcProgramObj.showData(node, false);
+            };*/
         }
     },
     updateCellValue: function (node, value, colSetting) {
@@ -258,12 +268,23 @@ var projectObj = {
             if (fieldName === 'code') {
                 projectObj.updateCode(node, value);
             } else if (fieldName === 'quantity' && project.quantity_detail.quantityEditChecking(value,node,fieldName)) {
+                if (value) {value = value.toDecimal(projectObj.project.Decimal.common.quantity);};
                 node.data.quantity = value;
+                node.changed = true;
                 project.calcProgram.calculate(node);
                 project.calcProgram.saveNode(node);
                 // projectObj.updateAndReCalculate(node, fieldName, value);
             } else if (fieldName === 'feesIndex.common.unitFee') {
-                projectObj.updateAndReCalculate(node, fieldName, value);
+                if (value) {value = value.toDecimal(projectObj.project.Decimal.common.unitFee);};
+                node.data.feesIndex.common.unitFee = value;
+                project.calcProgram.calculate(node);
+                project.calcProgram.saveNode(node);
+                // projectObj.updateAndReCalculate(node, fieldName, value);
+            } else if (fieldName === 'programID') {
+                node.data.programID = value;
+                node.changed = true;
+                project.calcProgram.calculate(node);
+                project.calcProgram.saveNode(node);
             } else if(fieldName ==='feeRate'){
                 project.FeeRate.updateFeeRateFromBills(value,node,fieldName);
             }else {
@@ -324,6 +345,7 @@ var projectObj = {
         this.project = PROJECT.createNew(scUrlUtil.GetQueryString('project'), userID);
         this.project.loadDatas(function (err) {
             if (!err) {
+                that.project.calcProgram.compileAllTemps();
                 that.project.calcFields = JSON.parse(JSON.stringify(feeType));
                 that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);
@@ -331,6 +353,13 @@ var projectObj = {
                 that.project.projSetting.mainGridSetting.frozenCols = 4;
                 TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
                 that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
+                    // for test.  后端没有绑定,暂时写死用于测试。
+                    if (col.data.field == '' && col.head.titleNames[0] == "取费专业") {
+                        col.data.field = 'programID';
+                        col.data.getText = 'getText.calcProgramName';
+                        col.data.cellType = 'cellType.calcProgramName';
+                    };
+
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
                         col.data.getText = MainTreeCol.getEvent(col.data.getText);
@@ -351,8 +380,6 @@ var projectObj = {
                     }
                 });
 
-                that.project.calcProgram.compileAllTemps();
-
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
                 that.mainController.showTreeData();
                 that.mainController.bind('refreshBaseActn', that.refreshBaseActn);
@@ -468,7 +495,8 @@ var projectObj = {
                 "calculateAll_RationContent": {
                     name: '造价计算',
                     callback: function () {
-                        projectObj.calculateAll();
+                        // projectObj.calculateAll();
+                        project.calcProgram.calcAllNodes();
                     }
                 }
             }
@@ -476,7 +504,7 @@ var projectObj = {
     },
     // 计算node及node的所有父项
     converseCalculateBills: function (node) {
-        if (node) {
+/*        if (node) {
             let calc = new BillsCalcHelper(this.project);
             calc.calcNode(node, true);
             let cur = node, nodes = [];
@@ -487,16 +515,18 @@ var projectObj = {
             this.mainController.refreshTreeNode(nodes, false);
             this.project.Bills.updateNodes(nodes, true);
             calc = null;
-        }
+        }*/
+        projectObj.project.calcProgram.calculate(node);
+        projectObj.project.calcProgram.saveNode(node);
     },
     // 计算全部清单
-    calculateAll: function () {
+/*    calculateAll: function () {
         let calc = new BillsCalcHelper(this.project);
         calc.calcAll();
         this.mainController.showTreeData();
         this.project.Bills.updateAll();
         calc = null;
-    }
+    }*/
 };
 
 $('#insert').click(function () {
@@ -620,10 +650,18 @@ $('#property_ok').click(function () {
         reCalc = true;
     }
     if (reCalc) {
-        projectObj.calculateAll();
-        project.pushNow('editBillsCalcMode',
+        // projectObj.calculateAll();
+/*        project.pushNow('editBillsCalcMode',
             [project.projSetting.moduleName, project.Bills.getSourceType()],
-            [{projectID: project.ID(), billsCalcMode: project.projSetting.billsCalcMode}, project.Bills.getUpdateAllData()]
-        );
+            [{
+                projectID: project.ID(),
+                billsCalcMode: project.projSetting.billsCalcMode
+            }, project.Bills.getUpdateAllData()]
+        );*/
+        project.pushNow('', [project.projSetting.moduleName], [{
+            projectID: project.ID(),
+            billsCalcMode: project.projSetting.billsCalcMode
+        }]);
+        project.calcProgram.calcAllNodes(calcAllType.catBills);
     }
 });

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

@@ -116,10 +116,12 @@ $("#linkTZJNR").click(function () {
     }
     gljOprObj.activeTab='#linkTZJNR';
 });
-function SubActiveSheetNameIs(sheetName){
-    let rst = subSpread.getActiveSheet().name() == sheetName;
+
+function activeSubSheetIs(idx){
+    let rst = subSpread.getActiveSheetIndex() == idx;
     return rst;
 }
+
 //弹出清单规则或定额库后导致subSpread和特征及内容spread显示出问题
 function refreshSubSpread(){
     if(pageCCOprObj.active){

+ 51 - 37
web/building_saas/pm/html/project-management.html

@@ -74,10 +74,15 @@
                         <div class="tab-pane active" id="pm_all" role="tabpanel">
                         <div class="toolsbar">
                             <div class="tools-btn btn-group align-top">
-                                <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
-                                <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
-                                <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
-                                <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
+                                <a href="javascript:void(0);"  id="add-tender-btn" class="btn btn-sm"><i class="fa fa-sticky-note-o"></i>新建单位工程</a>
+                                <div class="btn-group" role="group">
+                                    <a href="javascript:void(0);" class="btn btn-sm dropdown-toggle" data-toggle="dropdown"></a>
+                                    <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
+                                        <a href="javascript:void(0);"  id="add-project-btn" class="dropdown-item"><i class="fa fa-cubes"></i>新建建设项目</a>
+                                        <a href="javascript:void(0);"  id="add-engineering-btn" class="dropdown-item disabled"><i class="fa fa-cube"></i> 新建单项工程</a>
+                                        <a href="javascript:void(0);"  id="add-folder-btn" class="dropdown-item"><i class="fa fa-folder-o"></i>新建文件夹</a>
+                                    </div>
+                                </div>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>
@@ -219,47 +224,28 @@
         </div>
     </div>
 </div>
+
 <!--弹出新建建设项目-->
 <div class="modal fade" id="add-project-dialog" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</h5>
+                <h5 class="modal-title">新建 <i class="fa fa-cubes"></i> 建设项目</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>
             </div>
             <div class="modal-body">
-                <!--没有点击任何节点-->
                 <form>
                     <div class="form-group">
                         <label>建设项目</label>
                         <input type="text" class="form-control" placeholder="输入建设项目名称" id="project-name">
                     </div>
-                    <div class="form-group">
-                        <label>计价方式</label>
-                        <div>
-                            <label class="custom-control custom-radio">
-                                <input name="valuation_type" type="radio" class="custom-control-input" value="bill">
-                                <span class="custom-control-indicator"></span>
-                                <span class="custom-control-description">清单计价</span>
-                            </label>
-                            <label class="custom-control custom-radio">
-                                <input name="valuation_type" type="radio" class="custom-control-input" value="ration">
-                                <span class="custom-control-indicator"></span>
-                                <span class="custom-control-description">定额计价</span>
-                            </label>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label>计价规则</label>
-                        <select class="form-control" id="valuation"><option value="">请选择计价规则</option></select>
-                    </div>
                 </form>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <a href="javacript:void(0);" class="btn btn-primary" id='addProjOk'>确定</a>
+                <a href="javascript:void(0);" class="btn btn-primary" id="addProjOk">确定</a>
             </div>
         </div>
     </div>
@@ -295,27 +281,51 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</h5>
+                <h5 class="modal-title">新建 <i class="fa fa-sticky-note-o"></i> 单位工程</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>
             </div>
             <div class="modal-body">
-                <!--没有点击任何节点-->
                 <form>
                     <div class="form-group">
-                        <label>单位工程</label>
-                        <input type="text" class="form-control" placeholder="输入单位工程名称" id="tender-name">
+                        <label>建设项目</label>
+                        <div class="input-group">
+                            <input type="text" class="form-control" placeholder="输入建设项目名称" id="poj-name" autocomplete="off">
+                              <span class="input-group-btn">
+                                <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"></button>
+                                <div class="dropdown-menu dropdown-menu-right" style="width:468px" id="poj-name-list">
+                                    <button class="dropdown-item" type="button">汽车生产车间1</button>
+                                    <button class="dropdown-item" type="button">汽车生产车间2</button>
+                                    <button class="dropdown-item" type="button">汽车生产车间3</button>
+                                </div>
+                              </span>
+                        </div>
+                        <span class="form-text text-info" id="poj-name-info" style="display: none;">新建 “汽车生产车间5”</span>
                     </div>
                     <div class="form-group">
-                        <label>工程专业</label>
-                        <select class="form-control" id="tender-engineering"><option>建筑工程</option></select>
+                        <label>单项工程</label>
+                        <div class="input-group">
+                            <input type="text" class="form-control" placeholder="输入单项工程名称" id="eng-name" autocomplete="off">
+                              <span class="input-group-btn">
+                                <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"></button>
+                                <div class="dropdown-menu dropdown-menu-right" style="width:468px" id="eng-name-list">
+                                    <button class="dropdown-item" type="button">左3号生产车间</button>
+                                    <button class="dropdown-item" type="button">左4号生产车间</button>
+                                </div>                              </span>
+                        </div>
+                        <span class="form-text text-info" id="eng-name-info" style="display: none;">新建 “左2号生产车间2”</span>
                     </div>
-                    <div class="form-group hidden-area">
+                    <div class="form-group">
+                        <label>单位工程</label>
+                        <input type="text" class="form-control" placeholder="输入单位工程名称" id="tender-name" autocomplete="off">
+                        <span class="form-text text-danger" id="tender-name-info" style="display: none;">已存在 “建筑工程1”</span>
+                    </div>
+                    <div class="form-group">
                         <label>单价文件</label>
                         <select class="form-control" id="unit-price"><option value="">新建单价文件</option></select>
                     </div>
-                    <div class="form-group hidden-area">
+                    <div class="form-group">
                         <label>费率文件</label>
                         <select class="form-control" id="tender-fee-rate"><option value="">新建费率文件</option></select>
                     </div>
@@ -323,12 +333,12 @@
                         <label>计价方式</label>
                         <div>
                             <label class="custom-control custom-radio">
-                                <input name="tender_valuation_type" type="radio" class="custom-control-input" value="bill" checked="checked">
+                                <input name="valuation_type" value="bill" type="radio" class="custom-control-input">
                                 <span class="custom-control-indicator"></span>
                                 <span class="custom-control-description">清单计价</span>
                             </label>
                             <label class="custom-control custom-radio">
-                                <input name="tender_valuation_type" type="radio" class="custom-control-input" value="ration" disabled="disabled">
+                                <input name="valuation_type" value="ration" type="radio" class="custom-control-input">
                                 <span class="custom-control-indicator"></span>
                                 <span class="custom-control-description">定额计价</span>
                             </label>
@@ -336,7 +346,11 @@
                     </div>
                     <div class="form-group">
                         <label>计价规则</label>
-                        <select class="form-control" id="tender-valuation" disabled><option>重庆[2008]调整人工单价</option></select>
+                        <select class="form-control" id="valuation"><option value="">请选择计价规则</option></select>
+                    </div>
+                    <div class="form-group">
+                        <label>工程专业</label>
+                        <select class="form-control" id="tender-engineering"><option value="">请选择对应的工程专业</option></select>
                     </div>
                 </form>
             </div>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 592 - 192
web/building_saas/pm/js/pm_main.js