Selaa lähdekoodia

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/YangHuCost

chenshilong 6 vuotta sitten
vanhempi
commit
07f55d99ea

+ 1 - 0
config/gulpConfig.js

@@ -17,6 +17,7 @@ module.exports = {
         'lib/lodash/lodash.js',
         'public/web/commonAlert.js',
         'public/web/headerOpr.js',
+        'public/common_util.js',
         'lib/jquery-editable-select/jquery.editable-select.min.js'
     ],
     common_css:[

+ 10 - 0
modules/all_models/ration_glj.js

@@ -34,6 +34,16 @@ var ration_glj = new Schema({
     customQuantity:String,
     rationItemQuantity:String,
     tenderQuantity:String,//调整后消耗量
+    // 定额配合比
+    rationProportion: {
+        type: Number,
+        default: 0
+    },
+    // 调整配合比
+    adjustProportion: {
+        type: Number,
+        default: 0
+    },
     createType: {type: String,default:'normal'},//normal、add、replace  正常、添加工料机、替换工料机
     from:{type: String,default:'std'}//std, cpt  来自标准工料机库、补充工料机库
 },{versionKey:false});

+ 10 - 8
modules/complementary_ration_lib/models/compleRationModel.js

@@ -166,14 +166,15 @@ class CompleRatoinDao {
             }
             if(!gUtil) gUtil = gljUtil;
             let gljDatas = gUtil.sortRationGLJ(stdGljs.concat(comGljs));
-            for(let glj of gljDatas){
-                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '   ' + glj.specs : ''} &nbsp ${glj.unit}   ${gljAmtMapping[glj.ID]}`)
-            }
-            hintsArr.push(`基价 元 ${ration.basePrice}`);
             if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
                 hintsArr.push(`工作内容:`);
                 hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+                hintsArr.push("");
             }
+            for(let glj of gljDatas){
+                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '   ' + glj.specs : ''} &nbsp ${glj.unit}   ${gljAmtMapping[glj.ID]}`)
+            }
+            hintsArr.push(`基价 元 ${ration.basePrice}`);
             if(ration.annotation && ration.annotation.toString().trim() !== ''){
                 hintsArr.push(`附注:`);
                 hintsArr = hintsArr.concat(ration.annotation.split('\n'));
@@ -243,14 +244,15 @@ class CompleRatoinDao {
             }
             if(!gUtil) gUtil = gljUtil;
             let gljDatas =  gUtil.sortRationGLJ(stdGljs);
-            for(let glj of gljDatas){
-                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '   ' + glj.specs : ''} &nbsp ${glj.unit}   ${gljAmtMapping[glj.ID]}`)
-            }
-            hintsArr.push(`基价 元 ${ration.basePrice}`);
             if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
                 hintsArr.push(`工作内容:`);
                 hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+                hintsArr.push("");
             }
+            for(let glj of gljDatas){
+                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '   ' + glj.specs : ''} &nbsp ${glj.unit}   ${gljAmtMapping[glj.ID]}`)
+            }
+            hintsArr.push(`基价 元 ${ration.basePrice}`);
             if(ration.annotation && ration.annotation.toString().trim() !== ''){
                 hintsArr.push(`附注:`);
                 hintsArr = hintsArr.concat(ration.annotation.split('\n'));

+ 7 - 1
modules/main/facade/ration_facade.js

@@ -512,6 +512,7 @@ async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
         }
         for(let sub of std.rationGljList){
             let newGLJ = {};
+            let proportion = sub.proportion || 0;
             newGLJ.ID = uuidV1();
             newGLJ.projectID = newRation.projectID;
             newGLJ.GLJID = sub.gljId;
@@ -520,6 +521,8 @@ async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
             newGLJ.rationItemQuantity = sub.consumeAmt;
             newGLJ.quantity = sub.consumeAmt;
             newGLJ.glj_repository_id = std.rationRepId;
+            newGLJ.rationProportion = proportion;
+            newGLJ.adjustProportion = proportion;
             let std_glj = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
             if(std_glj){
                 ration_glj_facade.setPropertyFromStd(newGLJ,std_glj);
@@ -591,7 +594,10 @@ async function updateCoeAdjust(data,compilation) {
     //替换工料机的情况
     if (data.replace.length > 0){
         for(let r of data.replace){
-            replace.push(await  ration_glj_facade.replaceGLJByData(r,compilation)) ;
+            let r_result = await  ration_glj_facade.replaceGLJByData(r,compilation);
+            replace.push(r_result.data) ;
+            if(r_result.newRecodes.length > 0) data.add = data.add.concat(r_result.newRecodes);
+            if(r_result.deleteList.length > 0) data.delete = data.delete.concat(r_result.deleteList);
         }
     }
     let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);

+ 12 - 1
modules/ration_glj/controllers/ration_glj_controller.js

@@ -16,7 +16,8 @@ module.exports={
     mReplaceGLJ:mReplaceGLJ,
     updateRationGLJByEdit:updateRationGLJByEdit,
     getGLJClass:getGLJClass,
-    deleteRationGLJ:deleteRationGLJ
+    deleteRationGLJ:deleteRationGLJ,
+    updateProportion:updateProportion
 }
 function createRationGLJ() {
     let gls = mongoose.model('ration_glj');
@@ -117,6 +118,16 @@ async function deleteRationGLJ (req,res) {
     res.json(result);
 }
 
+async function updateProportion(req, res) {
+    try {
+        const data = JSON.parse(req.body.data);
+        const rst = await ration_glj_facade.updateProportion(data.proportionList, data.projectID, data.rationID);
+        res.json({ error: 0, data: rst, message: 'success' });
+    } catch (err) {
+        res.json({ error: 1, data: null, message: err.message });
+    }
+}
+
 async function replaceGLJ(req, res){
     let result={
         error:0

+ 79 - 63
modules/ration_glj/facade/glj_calculate_facade.js

@@ -16,20 +16,22 @@ let glj_type_util = require('../../../public/cache/std_glj_type_util');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let decimal_facade = require('../../main/facade/decimal_facade');
 let gljUtil = require('../../../public/gljUtil');
+const common_util = require('../../../public/common_util');
 
 module.exports={
     calculateQuantity:calculateQuantity,
     getGLJTypeByID:getGLJTypeByID
 }
-//辅助定额调整、替换工料机、标准附注条件调整、添加工料机、自定义消耗量(包括删除工料机)、自定义乘系数、市场单价调整
+//辅助定额调整、稳定土配合比、替换工料机、标准附注条件调整、添加工料机、自定义消耗量(包括删除工料机)、自定义乘系数、市场单价调整
 let stateSeq ={
     ass:1,
-    replace:2,
-    coe:3,
-    add:4,
-    cusQuantity:5,
-    cusCoe:6,
-    adjMak:7
+    proportion: 2,
+    replace:3,
+    coe:4,
+    add:5,
+    cusQuantity:6,
+    cusCoe:7,
+    adjMak:8
 };
 //自定义乘系数与定额工料机类型映射表
 let coeTypeMap = {
@@ -44,66 +46,71 @@ let coeTypeMap = {
 
 async function calculateQuantity(query,noNeedCal=null,refreshRationName = false){
     try {
-         let  result ={
-             glj_result:[],
-             rationID:query.rationID
-         };
-         let impactRation = await ration.findOne({ID:query.rationID});
-         let gljList = await ration_glj.find(query);//{projectID:query.projectID,rationID:query.rationID}
-         let coeList = await ration_coe.find({rationID:query.rationID}).sort('seq').exec();
-         let assList=[], assRation = null, adjustState=[],mixRatioMap = {};
-         if(!impactRation){//如果定额不存在或者已删除,返回空
-             return null;
-         }
-         if(impactRation._doc.hasOwnProperty("rationAssList")&&impactRation.rationAssList.length>0){
-             prepareAss(impactRation.rationAssList);
-             let temTimes = [];
-             let thirdRationCodes=[];
-             for(let i=0;i<impactRation.rationAssList.length;i++){
-                 let times = calculateTimes(impactRation.rationAssList[i]);
-                 if(times!=0){
-                     let thirdRationCode = impactRation.rationAssList[i].thirdRationCode;
-                     if(thirdRationCode && thirdRationCode !=''){
-                         temTimes.push(times);
-                         thirdRationCodes.push(thirdRationCode)
-                     }
-                     assRation = await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:impactRation.rationAssList[i].assistCode});
-                     assList.push({times:times,assRation:assRation});
-                     adjustState.push({index:stateSeq.ass,content:impactRation.rationAssList[i].name+" "+impactRation.rationAssList[i].actualValue+" : +"+impactRation.rationAssList[i].assistCode+"x"+times});
-                 }
-             }
-             if(temTimes.length == 2 &&thirdRationCodes[0] == thirdRationCodes[1] ){ //说明有第三定额
-                 let times_t = temTimes[0] * temTimes[1];
-                 let tration =  await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:thirdRationCodes[0]});
-                 if(tration){
-                     assList.push({times:times_t,assRation:tration});
-                     adjustState.push({index:stateSeq.ass,content:"+"+thirdRationCodes[0]+"x"+times_t});
-                 }
-             }
-         }
-         for(let glj of gljList){//先把混凝土,砂浆,配合比有自定义消耗的挑出来
-             if(gljUtil.isConcreteType(glj.type)) await getMixRatioMap(glj,gljList,coeList,assList,mixRatioMap);
-         }
+        let  result ={
+            glj_result:[],
+            rationID:query.rationID
+        };
+        let impactRation = await ration.findOne({ID:query.rationID});
+        let gljList = await ration_glj.find(query);//{projectID:query.projectID,rationID:query.rationID}
+        let coeList = await ration_coe.find({rationID:query.rationID}).sort('seq').exec();
+        let assList=[], assRation = null, adjustState=[],mixRatioMap = {};
+        if(!impactRation){//如果定额不存在或者已删除,返回空
+            return null;
+        }
+        if(impactRation._doc.hasOwnProperty("rationAssList")&&impactRation.rationAssList.length>0){
+            prepareAss(impactRation.rationAssList);
+            let temTimes = [];
+            let thirdRationCodes=[];
+            for(let i=0;i<impactRation.rationAssList.length;i++){
+                let times = calculateTimes(impactRation.rationAssList[i]);
+                if(times!=0){
+                    let thirdRationCode = impactRation.rationAssList[i].thirdRationCode;
+                    if(thirdRationCode && thirdRationCode !=''){
+                        temTimes.push(times);
+                        thirdRationCodes.push(thirdRationCode)
+                    }
+                    assRation = await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:impactRation.rationAssList[i].assistCode});
+                    assList.push({times:times,assRation:assRation});
+                    adjustState.push({index:stateSeq.ass,content:impactRation.rationAssList[i].name+" "+impactRation.rationAssList[i].actualValue+" : +"+impactRation.rationAssList[i].assistCode+"x"+times});
+                }
+            }
+            if(temTimes.length == 2 &&thirdRationCodes[0] == thirdRationCodes[1] ){ //说明有第三定额
+                let times_t = temTimes[0] * temTimes[1];
+                let tration =  await  std_ration_lib_ration_items.findOne({rationRepId:impactRation.libID,code:thirdRationCodes[0]});
+                if(tration){
+                    assList.push({times:times_t,assRation:tration});
+                    adjustState.push({index:stateSeq.ass,content:"+"+thirdRationCodes[0]+"x"+times_t});
+                }
+            }
+        }
+        // 稳定土调整状态
+        const proportionStr = gljList.filter(glj => glj.rationProportion).map(glj => glj.adjustProportion || 0).join(':');
+        if (proportionStr) {
+            adjustState.push({ index: stateSeq.proportion, content: proportionStr });
+        }
+        for(let glj of gljList){//先把混凝土,砂浆,配合比有自定义消耗的挑出来
+            if(gljUtil.isConcreteType(glj.type)) await getMixRatioMap(glj,gljList,coeList,assList,mixRatioMap);
+        }
         gljList = gljUtil.sortRationGLJ(gljList);
         for(let i =0;i<gljList.length;i++ ){
             let r = await calculateQuantityPerGLJ(gljList[i],gljList,coeList,assList,adjustState,mixRatioMap,noNeedCal);
             if(quantityUpdateCheck(gljList[i],r) == true) result.glj_result.push(r);
         }
-         if(noNeedCal==null && result.glj_result.length > 0){
-             await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
-         }
-         adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
-         adjustState=_.map(adjustState, _.property('content'));
-         let adjustStateString = adjustState.join(';');
-         let setData = {adjustState:adjustStateString};
-         if(refreshRationName == true){//需要更新定额名称
-             let newName = generateRationName(impactRation,gljList);
-             setData.name = newName;
-             result.rationName = newName;
-         }
-         await ration.update({ID:query.rationID},setData);
-         result.adjustState=adjustStateString;
-         return result;
+        if(noNeedCal==null && result.glj_result.length > 0){
+            await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
+        }
+        adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
+        adjustState=_.map(adjustState, _.property('content'));
+        let adjustStateString = adjustState.join(';');
+        let setData = {adjustState:adjustStateString};
+        if(refreshRationName == true){//需要更新定额名称
+            let newName = generateRationName(impactRation,gljList);
+            setData.name = newName;
+            result.rationName = newName;
+        }
+        await ration.update({ID:query.rationID},setData);
+        result.adjustState=adjustStateString;
+        return result;
     }catch (err){
         console.log(err);
         throw err;
@@ -141,6 +148,11 @@ function generateRationName(ration,gljList) {
             caption =  caption.replace('%s',r);
         }
     }
+    // 更新定额名称中显示的稳定土配合比
+    const proportionStr = gljList.filter(glj => glj.rationProportion).map(glj => glj.adjustProportion || 0).join(':');
+    if (proportionStr) {
+        caption = caption.replace('%p', proportionStr);
+    }
     let reNameList = [];
     for(let g of gljList){
         //glj._doc.createType=='replace'&&glj.rcode!=glj.code
@@ -175,6 +187,10 @@ function generateUpdateTasks(result) {
 async function calcWhenNoCustomQuantiyt(decimal,glj,gljList,coeList,assList) {
     let quantity = glj.rationItemQuantity ? scMathUtil.roundTo(parseFloat(glj.rationItemQuantity),-decimal):0;
     quantity =scMathUtil.roundTo(await calculateAss(quantity,assList,glj),-decimal);
+    if (glj.rationProportion && common_util.isDef(glj.adjustProportion)) {
+        const proportionRate = glj.adjustProportion / glj.rationProportion;
+        quantity *= proportionRate;
+    }
     quantity = calculateQuantityByCoes(quantity,coeList,glj,gljList,decimal);
     return quantity;
 }
@@ -193,7 +209,7 @@ async function calculateQuantityPerGLJ(glj,gljList,coeList,assList,adjustState,m
         }
     };
     try {
-        if(noNeedCal==null){//计算顺序:辅助定额,附注条件,自定义消耗(如果有就不用前计算两项),自定义乘系数
+        if(noNeedCal==null){//计算顺序:辅助定额, 稳定土配合比、附注条件,自定义消耗(如果有就不用前计算两项),自定义乘系数
             if(noCustomQuantiyt(glj)){
                 quantity = await calcWhenNoCustomQuantiyt(decimal,glj,gljList,coeList,assList);
                 let mIndex = gljUtil.getIndex(glj);

+ 29 - 1
modules/ration_glj/facade/ration_glj_facade.js

@@ -27,7 +27,8 @@ module.exports = {//先 exports再require 防止循环引用
     updateRationGLJFromDoc:updateRationGLJFromDoc,
     getGLJLibByEngineerID:getGLJLibByEngineerID,
     prepareExtData:prepareExtData,
-    setPropertyFromStd:setPropertyFromStd
+    setPropertyFromStd:setPropertyFromStd,
+    updateProportion: updateProportion
 };
 
 let mongoose = require('mongoose');
@@ -171,6 +172,8 @@ function createNewRecord(ration_glj) {
     newRecoed.rationItemQuantity = ration_glj.rationItemQuantity;
     newRecoed.customQuantity = ration_glj.customQuantity;
     newRecoed.quantity = ration_glj.quantity;
+    newRecoed.rationProportion = ration_glj.rationProportion;
+    newRecoed.adjustProportion = ration_glj.adjustProportion;
     newRecoed.name = ration_glj.name;
     newRecoed.code = ration_glj.code;
     newRecoed.original_code = ration_glj.original_code;
@@ -967,6 +970,31 @@ async function doRationGLJUpdate(data) {
     return resutl;
 }
 
+async function updateProportion(proportionList, projectID, rationID) {
+    const bulks = proportionList.map(item => {
+        return {
+            updateOne: {
+                filter: {ID: item.ID},
+                update: {$set: {adjustProportion: item.adjustProportion}}
+            }
+        }
+    });
+    if (bulks.length) {
+        await ration_glj.bulkWrite(bulks);
+    }
+    const calcRst = await glj_calculate_facade.calculateQuantity({ projectID, rationID }, null, true);
+    const rationGLJ = {
+        quantityRefresh: true,
+        glj_result: calcRst.glj_result
+    };
+    const ration = {
+        ID: calcRst.rationID,
+        adjustState: calcRst.adjustState,
+        name: calcRst.rationName
+    };
+    return { ration_glj: rationGLJ, ration, add:[], delete:[], replace: [] };
+}
+
 async function getGLJClass(info, data) {
     let result = {
         exist: false

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

@@ -16,6 +16,7 @@ module.exports = function (app) {
     rgRouter.post('/updateRationGLJByEdit',rgController.updateRationGLJByEdit);
     rgRouter.post('/getGLJClass/:engineerID', rgController.getGLJClass);
     rgRouter.post('/deleteRationGLJ', rgController.deleteRationGLJ);
+    rgRouter.post('/updateProportion', rgController.updateProportion);
 
     app.use('/rationGlj',rgRouter);
 }

+ 30 - 0
public/common_util.js

@@ -0,0 +1,30 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/11/12
+ * @version
+ */
+
+((factory) => {
+    if (typeof module !== 'undefined') {
+        module.exports = factory();
+    } else {
+        window._commonUtil = factory();
+    }
+})(() => {
+    function isDef(val) {
+        return typeof val !== 'undefined' && val !== null;
+    }
+    
+    function isEmptyVal(val) {
+        return val === null || val === undefined || val === '';
+    }
+
+    return {
+        isDef,
+        isEmptyVal
+    };
+});

+ 6 - 1
public/gljUtil.js

@@ -23,7 +23,8 @@ module.exports = {
     sortRationGLJ:sortRationGLJ,
     sortProjectGLJ:sortProjectGLJ,
     getCCSProjectGLJ:getCCSProjectGLJ,
-    getBaseCCSMixRatio:getBaseCCSMixRatio
+    getBaseCCSMixRatio:getBaseCCSMixRatio,
+    setMaterialCalcRationFee:setMaterialCalcRationFee
 };
 
 function calcProjectGLJQuantity(projectGLJDatas,rationGLJDatas,rationDatas,billsDatas,q_decimal) {
@@ -34,6 +35,10 @@ function getGLJPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,i
     return gljNodeUtil.getGLJPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
 }
 
+function setMaterialCalcRationFee(ration,ration_gljs,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,_,scMathUtil) {
+    return gljNodeUtil.setMaterialCalcRationFee(ration,ration_gljs,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,_,scMathUtil);
+}
+
 function getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio=false) {
     return gljNodeUtil.getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
 }

+ 39 - 0
public/web/gljUtil.js

@@ -428,6 +428,45 @@ let gljUtil = {
             return scMathUtil.roundToString(quantity * glj.quantity, gd);
         }
     },
+    setMaterialCalcRationFee:function (ration,ration_gljs,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,_,scMathUtil) {
+        let pMap =_.indexBy(projectGLJDatas.gljList, 'id');
+        let process_decimal = decimalObj.process;
+        let ration_quantity_decimal = decimalObj.ration.quantity;
+        let glj_quantity_decimal = decimalObj.glj.quantity;
+        let glj_unitPrice_decimal = decimalObj.glj.unitPrice;
+        let assFeeRate = scMathUtil.roundForObj(projectGLJDatas.constData.assistProductionFeeRate,decimalObj.feeRate) * 0.01;//辅助生产间接费费率
+        let rationLaberFee = 0;  //定额人工费(市场价)
+        let rationMachineFee = 0; //定额施工机械使用费(市场价)
+        let rationLaberFee_b = 0;  //定额人工费(定额价)
+        let rationMachineFee_b = 0; //定额施工机械使用费(定额价)
+        let directFee = 0;//直接费
+        let rationQuantity = scMathUtil.roundForObj(ration.quantity,ration_quantity_decimal);
+        for(let g of ration_gljs){
+            let result = gljUtil.getGLJPrice(pMap[g.projectGLJID],projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,false,_,scMathUtil);
+            g.marketPrice = result.marketPrice;
+            g.basePrice = result.basePrice;
+            let quantity = scMathUtil.roundForObj(g.quantity,glj_quantity_decimal);
+            let t = scMathUtil.roundForObj(quantity * g.marketPrice * rationQuantity,process_decimal);//市场价
+            let rt = scMathUtil.roundForObj(quantity * g.basePrice * rationQuantity,process_decimal);//定额价
+            if(g.type == gljUtil.gljType.LABOUR){
+                rationLaberFee = scMathUtil.roundForObj(rationLaberFee+t,process_decimal);
+                rationLaberFee_b = scMathUtil.roundForObj(rationLaberFee_b+rt,process_decimal);
+            }else if(gljUtil.getMainType(g.type) == 3){
+                rationMachineFee = scMathUtil.roundForObj(rationMachineFee+t,process_decimal);
+                rationMachineFee_b = scMathUtil.roundForObj(rationMachineFee_b+rt,process_decimal);
+            }
+            directFee = scMathUtil.roundForObj(directFee + t,process_decimal);
+        }
+        ration.assistProductionFee = scMathUtil.roundForObj(rationLaberFee_b * assFeeRate,glj_unitPrice_decimal);//辅助生产间接费
+        ration.rationLaberFee = scMathUtil.roundForObj(rationLaberFee,glj_unitPrice_decimal);//定额人工费(市场价)
+        ration.rationMachineFee = scMathUtil.roundForObj(rationMachineFee,glj_unitPrice_decimal);//定额施工机械使用费(市场价)
+        ration.directFee = scMathUtil.roundForObj(directFee,glj_unitPrice_decimal);//直接费
+        //to do 高原取费类别的情况待确认
+        //let hs = scMathUtil.roundForObj(tt*hightFeeRate,process_decimal);//(人工定额消耗量*定额价*定额工程量+机械定额消耗量*定额价*定额工程量)*高原取费类别费率
+
+    },
+
+
     fixedFlag : {
         // 分部分项工程
         SUB_ENGINERRING: 1,

+ 3 - 0
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -118,6 +118,9 @@ var rationGLJOprObj = {
                                 gljSelOprObj.initClassTree('std', gljSelOprObj.treeData.std);
                                 //弹出窗口
                                 $('#selGlj').modal('show');
+                                if (gljSelOprObj.workBook) {
+                                    gljSelOprObj.workBook.refresh();
+                                }
                             }},
                             "delete": {name: "删除工料机", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
                                 rationGlj.splice(target.row, 1);

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

@@ -242,6 +242,9 @@
                                                   <div class="tab-pane" id="rnc-fz">
                                                       <div class="main-data-bottom ovf-hidden" id="assSpread"></div>
                                                   </div>
+                                                  <div class="tab-pane" id="rnc-stable">
+                                                      <div class="main-data-bottom ovf-hidden" id="stableSpread"></div>
+                                                  </div>
                                               </div>
                                              <!-- <div class="p-0" id="openItemText" style="height:100%;width: 40px">
                                                   <div class="tn-nav d-flex align-items-start flex-column" data-toggle="tooltip" data-placement="left" title="" data-original-title="打开项目特征">
@@ -271,6 +274,7 @@
                                                           </li>-->
                                                           <li class="nav-item" data-toggle="tooltip" data-placement="left" title="附注条件"><a data-toggle="tab"  id="hs-nav" href="#rnc-zm" role="tab"class="zmhs-link nav-link">换算<!--<i class="fa fa-check-circle-o"></i>--></a></li>
                                                           <li class="nav-item" data-toggle="tooltip" data-placement="left" title="自定义系数"><a data-toggle="tab" href="#rnc-cus" role="tab"class="zmhs-link nav-link">系数<!--<i class="fa fa-wrench"></i>--></a></li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="定额稳定土"><a data-toggle="tab" href="#rnc-stable" role="tab" class="zmhs-link nav-link">稳定土</a></li>
                                                           <!--                     <li class="nav-item" data-toggle="tooltip" data-placement="left" title="增减换算"><a data-toggle="tab" href="#rnc-fz" role="tab"class="zmhs-link nav-link "><i class="fa fa-plus"></i></a></li>-->
                                                         <!--  <li class="nav-item"><a data-toggle="tab" href="#rnc-xm" role="tab"  class="nav-link">项目特征</a></li>
                                                           <li class="nav-item"><a data-toggle="tab" href="#rnc-zm" role="tab" class="nav-link">子目换算</a></li>
@@ -804,7 +808,7 @@
                                 <div class="tab-pane fade" id="poj-settings-decimal" role="tabpanel">
                                     <div class="modal-auto-height">
                                         <fieldset class="form-group">
-                                            <h5>清单</h5>
+                                            <h5 id="bills_decimal_header">清单</h5>
                                             <div class="row m-0">
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">

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

@@ -342,11 +342,25 @@ var Bills = {
         };
         bills.prototype.downLevelBills = function (node) {
             var downLevelData = node.getDownLevelData();
+            this.setQuantityAfterDownLevel(node,downLevelData);
             project.pushNow('downLevelBills', [this.getSourceType()], [tools.coverseTreeUpdateData(downLevelData, this.project.ID())]);
 
             return node.downLevel();
         };
+        bills.prototype.setQuantityAfterDownLevel = function (node,downLevelData) {
+            if(projectObj.project.projectInfo.property && projectObj.project.projectInfo.property.valuationType == "ration"){//工程量清单项目中,将B降级为A的子项后应清空A的工程量
+                let preNode = node.preSibling;
+                for(let d of downLevelData){
+                    if(preNode && preNode.getID()==d.data.ID){
+                        d.data.quantity = "0";
+                        d.data.quantityEXP = "";
+                        preNode.data.quantity = "0";
+                        preNode.data.quantityEXP = "";
+                    }
+                }
+            }
 
+        };
         bills.prototype.updateField = function (node, field, newValue,toBX) {//当toBX为true时类型改为补项
             calcFees.setFee(node.data, field, newValue);
             let updateData = [];

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

@@ -700,7 +700,6 @@ ProjectGLJ.prototype.updateUserFreight =async function (data) {
 ProjectGLJ.prototype.getUserFreights = async function () {//初始化车船税选择
     try {
         let result =  await ajaxGet("/glj/getUserFreights");
-        console.log(result);
         return result;
     }catch (e){
         console.log(e)
@@ -878,7 +877,6 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
     function calcRation(ration,gljs,pMap,priceMap){
         let result = 0;
         if(gljs){
-            //to do 计算有辅助定额的情况
             let processDecimal = getDecimal("process");
             let hightFeeRate = projectObj.project.projectGLJ.getHighlandFee(ration.feeType);//高原取费类别费率
             let assFeeRate = scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.assistProductionFeeRate,getDecimal("feeRate")) * 0.01;//辅助生产间接费费率

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

@@ -494,8 +494,7 @@ let ration_glj = {
                 projectObj.project.projectGLJ.loadData(function () {//等项目工料机加载完成后再给用户编辑
                     me.refreshTreeNodeIfNeeded(recode);//刷新造价书上的树节点(如果需要)
                     me.reCalcWhenGLJChange(recode);//触发计算定额以及父节点
-                    gljOprObj.refreshView();
-                    $.bootstrapLoading.end();
+					zmhs_obj.refreshStableDataIfNeeded();                    $.bootstrapLoading.end();
                     installationFeeObj.calcInstallationFee();
                 });
             };
@@ -1023,6 +1022,28 @@ let ration_glj = {
             }
             project.calcProgram.calcNodesAndSave(nodes);
         };
+        ration_glj.prototype.updateProportion = function (proportionList, projectID, rationID) {
+            const postData = {
+                proportionList,
+                projectID,
+                rationID
+            };
+            $.bootstrapLoading.start();
+            CommonAjax.post('/rationGLJ/updateProportion', postData, function (rst) {
+                proportionList.forEach(item => {
+                    const glj = zmhs_obj.stableSheetData.find(glj => glj.ID === item.ID);
+                    if (glj) {
+                        glj.adjustProportion = item.adjustProportion;
+                    }
+                });
+                zmhs_obj.refreshStableDataIfNeeded();
+                zmhs_obj.refreshAfterUpdate(rst);
+                $.bootstrapLoading.end();
+            }, function () {
+                zmhs_obj.refreshStableDataIfNeeded();
+                $.bootstrapLoading.end();
+            });
+        };
         return new ration_glj(project);
     }
 };

+ 23 - 0
web/building_saas/main/js/views/glj_view.js

@@ -745,6 +745,29 @@ var gljOprObj = {
         return data;
 
     },
+   /* testMaterialRationFee:function () {
+        let freightID = "8db5ff10-f495-11e9-bbf9-ef28356eebc5";
+        let rationID = "da995300-05f1-11ea-8265-63369b476c76";
+        let proGLJ =  projectObj.project.projectGLJ;
+        let freightList =  proGLJ.datas.freightList;
+        let calcOptions=projectObj.project.projectInfo.property.calcOptions;
+        let decimalObj = projectObj.project.projectInfo.property.decimal;
+        let labourCoeDatas =  projectObj.project.labourCoe.datas;
+        for(let f of freightList){
+            if(f.ID == freightID){
+                let r = null;
+                let ration_gljs = [];
+                for(let ration of f.rations){
+                    if(ration.ID == rationID) r = ration;
+                }
+                for(let rg of f.ration_gljs){
+                    if(rg.rationID == rationID) ration_gljs.push(rg);
+                }
+                gljUtil.setMaterialCalcRationFee(r,ration_gljs,proGLJ.datas,calcOptions,labourCoeDatas,decimalObj,_,scMathUtil)
+                console.log(r);
+            }
+        }
+    },*/
 
     getBasePrice:function (treeNode) {//造价书中的工料机修改的节点要用到
         let proGLJ =  projectObj.project.projectGLJ;

+ 5 - 4
web/building_saas/main/js/views/main_tree_col.js

@@ -468,13 +468,14 @@ let MainTreeCol = {
         let ration_glj = projectObj.project.ration_glj;
         let gljList = gljOprObj.filterGljByRation(node.data, ration_glj.datas);
         gljList = gljUtil.sortRationGLJ(gljList);
-        for(let glj of gljList){
-            tips += `${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${glj.quantity}<br>`;
-        }
         if(node.data.content && node.data.content.toString().trim() !== ''){
             tips += `工作内容:<br>`;
-            tips += `${node.data.content.replace(/\n/g,"<br>")}<br>`;
+            tips += `${node.data.content.replace(/\n/g,"<br>")}<br><br>`;
         }
+        for(let glj of gljList){
+            tips += `${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${glj.quantity}<br>`;
+        }
+
         if(node.data.annotation && node.data.annotation.toString().trim() !== ''){
             tips += `附注:<br>`;
             tips += `${node.data.annotation.replace(/\n/g,"<br>")}<br>`;

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

@@ -286,7 +286,10 @@ $(document).ready(function () {
     $('#poj-set').on('shown.bs.modal', function (e) {
         let v_data = m_getInitData(decimalObj);
         v_initPanel(v_data);
+        let headerText =  projectObj.project.projectInfo.property && projectObj.project.projectInfo.property.valuationType == "bill"?"项目节":"清单";//项目属性-小数位数,“清单”改文字为“项目节”,工程量清单中保持不变。
+        $("#bills_decimal_header").text(headerText);
     });
+
     //绑定确定按钮
     //e_bindCof($('#property_ok'));
     //绑定小数位数输入控制

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

@@ -1151,7 +1151,8 @@ var projectObj = {
     },
     loadMainSpreadContextMenu: function () {
         var project = this.project, spread = this.mainSpread, controller = this.mainController;
-        $.contextMenu({
+        let insertBillsName = project.projectInfo.property && project.projectInfo.property.valuationType == "bill"?"插入项目节":"插入清单";//右键“插入清单”改文字为“插入项目节”,工程量清单中保持不变。
+            $.contextMenu({
             selector: '#billsSpread',
             selectableSubMenu: true,
             build: function ($trigger, e) {
@@ -1251,7 +1252,7 @@ var projectObj = {
                     }
                 },
                 "insertBills": {
-                    name: "插入清单",
+                    name: insertBillsName,
                     icon: 'fa-sign-in',
                     disabled: function () {
                         if (projectReadOnly) {

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

@@ -282,7 +282,7 @@ function refreshSubSpread(){
     if(MaterialController.spread) MaterialController.spread.refresh();
     BillsElf.refreshWorkBook();
     //if($('#linkZMHS').hasClass('active')) zmhs_obj.refresh();
-    if($('#rnc-zm').is(':visible')|| $('#rnc-fz').is(':visible') || $('#rnc-cus')) zmhs_obj.refresh();
+    if($('#rnc-zm').is(':visible')|| $('#rnc-fz').is(':visible') || $('#rnc-cus') || $('#rnc-stable').is(':visible')) zmhs_obj.refresh();
     if($('#linkMBZM').hasClass('active')) mbzm_obj.refresh();
 }
 
@@ -404,6 +404,8 @@ $('.gljSubTab ul li a').on('shown.bs.tab', function () {
         zmhs_obj.initAssSpread();
     }else if(this.hash == "#rnc-cus"){
         zmhs_obj.initCusSpread();
+    }else if(this.hash == "#rnc-stable"){
+        zmhs_obj.initStableSpread();
     }
     zmhs_obj.refresh();
     zmhs_obj.showDatas();

+ 133 - 4
web/building_saas/main/js/views/zmhs_view.js

@@ -70,6 +70,21 @@ let zmhs_obj = {
         },
         emptyRowHeader: true
     },
+    stableSpread:null,
+    stableSheet:null,
+    stableSheetData:null,
+    stableSetting:{
+        header: [
+            {headerName: "材料编号", headerWidth: 100, dataCode: "code", dataType: "String"},
+            {headerName: "材料名称", headerWidth: 100, dataCode: "name", dataType: "String"},
+            {headerName: "调整配合比", headerWidth: 80, dataCode: "adjustProportion", dataType: "String", hAlign: "right", validator:"number", precision: 2}
+        ],
+        view: {
+            lockColumns:["code", "name"],
+            rowHeaderWidth:25
+        },
+        emptyRowHeader: true
+    },
     initSpread:function () {
         this.initCoeSpread();
         this.initAssSpread();
@@ -115,6 +130,18 @@ let zmhs_obj = {
             SheetDataHelper.protectdSheet(this.assSheet);
         }
     },
+    initStableSpread:function () {
+        if(zmhs_obj.stableSpread == null){
+            this.stableSpread = SheetDataHelper.createNewSpread($("#stableSpread")[0]);
+            sheetCommonObj.spreadDefaultStyle(this.stableSpread);
+            this.stableSheet = this.stableSpread.getSheet(0);
+            sheetCommonObj.initSheet(this.stableSheet, this.stableSetting, 30);
+            this.stableSheet.name('ration_stable');
+            this.stableSheet.bind(GC.Spread.Sheets.Events.ValueChanged,this.onStableValueChange);
+            this.stableSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onStableRangeChanged);
+            SheetDataHelper.protectdSheet(this.stableSheet);
+        }
+    },
     showCoeData:function (node) {
         let preSelections = this.coeSheet.getSelections();
         let selected = node?node:projectObj.project.mainTree.selected;
@@ -170,7 +197,18 @@ let zmhs_obj = {
             disableSpread(zmhs_obj.cusSpread);
         }
     },
-
+    showStableData: function (node) {
+        // 过滤出定额配合比不为0的数据
+        const stableList = gljOprObj.sheetData.filter(glj => !glj.isMixRatio && glj.rationProportion);
+        this.stableSheetData = stableList;
+        sheetCommonObj.showData(this.stableSheet, this.stableSetting, stableList);
+        const proportionCol = this.stableSetting.header.findIndex(item => item.dataCode === 'adjustProportion');
+        this.stableSheet.getRange(0, proportionCol, stableList.length, 1, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+        this.stableSheet.getRange(stableList.length, -1, this.stableSheet.getRowCount() - stableList.length, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+        if(projectReadOnly){
+            disableSpread(zmhs_obj.cusSpread);
+        }
+    },
     getComboBoxForCodes:function (coe,i) {
         this.coeSheet.getCell(i, 1, GC.Spread.Sheets.SheetArea.viewport).locked(false);
         let options = coe.option_list; //coe.option_codes.split("|");
@@ -221,8 +259,8 @@ let zmhs_obj = {
             }
         }
         projectObj.mainController.refreshTreeNode(nodes, false);
-
-        let rationID= ration_glj.updateCacheAfterAdjust(result.ration_glj);
+        let rationID = result.ration.ID;
+        ration_glj.updateCacheAfterAdjust(result.ration_glj);
         if(result.projectGLJDatas){//有添加、替换、工料机等需重新加载的情况
             projectObj.project.projectGLJ.refreshByDatas(result.projectGLJDatas);
             if(result.add && result.add.length > 0) ration_glj.addToMainTree(result.add);//这个方法有再去项目工料机那里取价格,所以要在回调里调用,不像替换工料的情况
@@ -231,7 +269,7 @@ let zmhs_obj = {
         }else {
             ration_glj.reCalcWhenGLJChange({rationID:rationID});
         }
-        gljOprObj.showRationGLJSheetData(true);
+        gljOprObj.refreshView();
     },
 
     deleteGLJs:function (IDs) {
@@ -261,12 +299,19 @@ let zmhs_obj = {
         $('#coeSpread').is(':visible')&&this.coeSpread?this.coeSpread.refresh():'';
         $('#cusSpread').is(':visible')&&this.cusSpread?this.cusSpread.refresh():'';
         $('#assSpread').is(':visible')&&this.assSpread?this.assSpread.refresh():'';
+        $('#stableSpread').is(':visible')&&this.stableSpread?this.stableSpread.refresh():'';
     },
     showDatas:function () {
         if($('#itemCharacterText').is(':visible'))MaterialController.showItemCharacterText()
         if($('#coeSpread').is(':visible')) this.showCoeData();
         if($('#cusSpread').is(':visible')) this.showCusData();
         if($('#assSpread').is(':visible')) this.showAssData();
+        if($('#stableSpread').is(':visible')) this.showStableData();
+    },
+    refreshStableDataIfNeeded: function () {
+        if ($('#stableSpread').is(':visible')) {
+            this.showStableData();
+        }
     },
     showZMHSData:function (node) {
         if(this.coeSpread&& this.assSpread && $('#linkZMHS').hasClass('active')){
@@ -554,6 +599,90 @@ let zmhs_obj = {
         }
         return true;
     },
+    onStableValueChange: function (e, args) {
+        const changeData = [{ row: args.row, col: args.col, value: args.newValue }];
+        zmhs_obj.changeStableValue(changeData);
+    },
+    onStableRangeChanged: function (e, args) {
+        const changeData = args.changedCells.map(cell => {
+            const value = args.sheet.getValue(cell.row, cell.col);
+            return { row: cell.row, col: cell.col, value};
+        });
+        zmhs_obj.changeStableValue(changeData);
+    },
+    changeStableValue: function (data) {
+        const isValid = data.every(cell => _commonUtil.isDef(cell.value) && sheetCommonObj.checkData(cell.col, this.stableSetting, cell.value));
+        if (!isValid) {
+            this.showDatas();
+            alert('输入的数据类型不对,请重新输入!');
+            return;
+        }
+        const precision = this.stableSetting.header.find(item => item.dataCode === 'adjustProportion').precision;
+        this.handleDataWithPrecision(data, precision);
+        const sheetData = this.getAutoStableSheetData(data, precision);
+        // 获取需要更新的数据
+        const rationGLJ = projectObj.project.ration_glj;
+        const updateProportionList = this.getStablePostData(sheetData);
+        const projectID = projectObj.project.ID();
+        const rationID = projectObj.project.mainTree.selected.data.ID;
+        rationGLJ.updateProportion(updateProportionList, projectID, rationID);
+    },
+    // 将值进行四舍五入处理
+    handleDataWithPrecision: function (data, precision) {
+        data.forEach(cell => {
+            cell.value = scMathUtil.roundTo(cell.value, -precision);
+        });
+    },
+    // 获取经过自动处理后的表格数据
+    getAutoStableSheetData: function (changedData, precision) {
+        const expectedValue = 100;
+        const unchangedData = [];
+        const col = this.stableSetting.header.findIndex(item => item.dataCode === 'adjustProportion');
+        this.stableSheetData.forEach((item, index) => {
+            const matchData = changedData.find(dItem => dItem.row === index);
+            if (!matchData) {
+                unchangedData.push({ row: index, col: col, value: item.adjustProportion});
+            }
+        });
+        // 稳定土各项调整配合比总值必须为100,不为100则自动调整某一项
+        const allData = _.sortBy(changedData.concat(unchangedData), 'row');
+        const total = allData.reduce((acc, cur) => scMathUtil.roundTo(acc + cur.value, -precision), 0);
+        if (total === expectedValue) {
+            return allData;
+        }
+        const autoAdjustData = getAutoAdjustData(changedData, unchangedData);
+        // 排除自动调整行后的总值
+        const exclusionTotal = allData.reduce((acc, cur) =>
+            cur.row !== autoAdjustData.row
+                ? scMathUtil.roundTo(acc + cur.value, -precision)
+                : acc + 0 , 0);
+        const autoAdjustValue = scMathUtil.roundTo(expectedValue - exclusionTotal, -precision);
+        autoAdjustData.value = autoAdjustValue;
+        return allData;
+        // 获取自动调整行数据
+        function getAutoAdjustData(changedData, unchangedData) {
+            debugger;
+            const changedMaxData = changedData[changedData.length - 1];
+            // 如果不存在不变的数据,自动调整行号为:最大变化数据行
+            if (!unchangedData.length) {
+                return changedMaxData;
+            }
+            const unchangedMinData = unchangedData[0];
+            // 如果存在不变的数据,则自动调整配合比的行数据为:比最大变化数据行大的行,或最小未变数据行
+            const greaterData = unchangedData.find(item => item.row > changedMaxData.row);
+            return greaterData ? greaterData : unchangedMinData;
+        }
+    },
+    getStablePostData: function (sheetData) {
+        const postData = [];
+        sheetData.forEach(cell => {
+            const originItem = this.stableSheetData[cell.row];
+            if (cell.value !== originItem.adjustProportion) {
+                postData.push({ ID: originItem.ID, adjustProportion: cell.value});
+            }
+        });
+        return postData;
+    },
     getSideResize: function () {
         let zmhs_sideResizeEles = {};
         zmhs_sideResizeEles.eleObj = {

+ 1 - 0
web/common/html/header.html

@@ -280,5 +280,6 @@
 <script type="text/javascript" src="/lib/lodash/lodash.js"></script>
 <script type="text/javascript" src="/public/web/commonAlert.js"></script>
 <script type="text/javascript" src="/public/web/headerOpr.js"></script>
+<script type="text/javascript" src="/public/common_util.js"></script>
 <script type="text/javascript" src="/lib/jquery-editable-select/jquery.editable-select.min.js"></script>
 <!-- endinject -->

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

@@ -167,7 +167,7 @@ if (typeof baseFigureTemplate !== 'undefined' && baseFigureTemplate.budget) {
     baseFigureTemplate.budget = {
         // 定额建筑安装工程费(定额设备购置费按40%计):取清单固定类别是“建筑安装工程”的定额建安费,其中定额设备购置费按40%计算
         DEJZAZGCFSBSS(tender) {
-            const feeField = 'rCommon';
+            const feeField = 'rationCommon';
             const subFeeField = tender ? 'tenderTotalFee' : 'totalFee';
             const deductFlags = [fixedFlag.EQUIPMENT_ACQUISITION_FEE];
             //建安费扣除定额设备购置费