Sfoglia il codice sorgente

智能材料替换和bugs

zhangweicheng 6 anni fa
parent
commit
eeafa44b57

+ 17 - 8
modules/main/controllers/material_replace_controller.js

@@ -4,16 +4,26 @@
 
 let materialFacade = require('../facade/material_replace_facade');
 let logger = require("../../../logs/log_helper").logger;
+let controller = {
+    getMaterial:async function(req) {
+        let data = req.body.data;
+        return await materialFacade.findMaterial(JSON.parse(data),req.session.sessionCompilation._id);
+
+    },
+    replace:async function(req){
+        let data = req.body.data;
+        return await materialFacade.replace(JSON.parse(data));
+    },
+};
+
 module.exports ={
-    findMaterial:async function(req,res) {
+    action:async function(req,res){//自动跳转到URL对应的controller方法
         let result={
             error:0
-        }
+        };
         try {
-            let data = req.body.data;
-            console.log(data);
-          //  data = JSON.parse(data);
-
+            let functionName = req.url.replace(/\//g,"");
+            result.data = controller[functionName]?await controller[functionName](req):"";
         }catch (err){
             logger.err(err);
             result.error=1;
@@ -21,5 +31,4 @@ module.exports ={
         }
         res.json(result);
     }
-
-};
+};

+ 42 - 75
modules/main/controllers/ration_controller.js

@@ -5,9 +5,39 @@ var rationData = require('../models/ration');
 var ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
 var ration_facade = require('../facade/ration_facade');
 let logger = require("../../../logs/log_helper").logger;
+let controller = {
+    insertGLJAsRation:async function (req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        return await ration_glj_facade.insertGLJAsRation(data);
+    },
+    replaceRations:async function (req) {
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let userID = req.session.sessionUser.id;
+        return await ration_facade.replaceRations(userID,data);
+    },
+    addNewRation:async function(req) {
+        let data = req.body.data;
+        if(typeof data === 'object'){
+            data = JSON.stringify(data);
+        }
+        data = JSON.parse(data);
+        return await ration_facade.addNewRation(data);
+    },
+    addMultiRation: async function (req) {
+        let data = req.body.data;
+        if(typeof data === 'object'){
+            data = JSON.stringify(data);
+        }
+        data = JSON.parse(data);
+        return await ration_facade.addMultiRation(data.newDatas);
+    }
+};
+
 
 //统一回调函数
-var callback = function(req, res, err, message, data){
+let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };
 
@@ -43,85 +73,22 @@ module.exports = {
             }
         });
     },
-    insertGLJAsRation:insertGLJAsRation,
-    replaceRations:replaceRations,
-    addNewRation:addNewRation,
-    addMultiRation: addMultiRation
-};
-
-async function addNewRation(req,res) {
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        if(typeof data === 'object'){
-            data = JSON.stringify(data);
+    action:async function(req,res){//自动跳转到URL对应的controller方法
+        let result={
+            error:0
         }
-        data = JSON.parse(data);
-        result.data = await ration_facade.addNewRation(data);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
-}
-
-async function addMultiRation(req,res) {
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        if(typeof data === 'object'){
-            data = JSON.stringify(data);
+        try {
+            let functionName = req.url.replace(/\//g,"");
+            result.data = controller[functionName]?await controller[functionName](req):"";
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
         }
-        data = JSON.parse(data);
-        console.log(`data`);
-        console.log(data);
-        result.data = await ration_facade.addMultiRation(data.newDatas);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
+        res.json(result);
     }
-    res.json(result);
-}
-
-async function replaceRations(req,res) {
-    let result={
-        error:0
-    };
-    try {
-        let data = req.body.data;
-        data = JSON.parse(data);
-        let userID = req.session.sessionUser.id;
-        result.data = await ration_facade.replaceRations(userID,data);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
 };
 
 
-async function insertGLJAsRation(req, res){
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        data = JSON.parse(data);
-        let datas= await ration_glj_facade.insertGLJAsRation(data);
-        result.data=datas;
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
 
 
-}

+ 119 - 0
modules/main/facade/material_replace_facade.js

@@ -1,3 +1,122 @@
 /**
  * Created by zhang on 2018/9/12.
  */
+let logger = require("../../../logs/log_helper").logger;
+let mongoose = require('mongoose');
+let material_lib = mongoose.model('std_material_replace_lib');
+let replace_bills = mongoose.model('std_replace_bills');
+let replace_material = mongoose.model('std_replace_material');
+let _=require("lodash");
+let ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
+let glj_calculate_facade = require('../../ration_glj/facade/glj_calculate_facade');
+
+
+module.exports = {
+    findMaterial: async function(dataMap,compilationId){
+        let libMap = {},resultMap={};
+        for(let key in dataMap) {
+            let billsLibId = dataMap[key].billsLibId;
+            let libID = libMap[compilationId + billsLibId] ? libMap[compilationId + billsLibId] : await getLibID(billsLibId, compilationId);
+            libMap[compilationId + billsLibId] = libID;
+            if (libID == null) continue;
+            let bills = await getBills(key, libID);
+            if (bills == null) continue;
+            let materialList = await getMaterialByBillsID(bills.ID);
+            resultMap[key] = {bills:bills,materialMap:_.indexBy(materialList,'code')};
+        }
+        return resultMap;
+    },
+    replace:async function(datas){
+        let resultList = [];
+        let rationMap = _.groupBy(datas,function(item){//先按定额进行分组
+            return item.glj.rationID;
+        });
+        for(let rationID in rationMap){
+           let result = await eachRationGroup(rationID,rationMap[rationID]);
+           resultList.push(result);
+        }
+        return resultList
+    }
+};
+
+async function eachRationGroup(rationID,datas) {
+    let query={rationID:rationID},gljs=[];
+    for(let d of datas){
+         query["projectID"] = d.glj.projectID;
+         gljs.push(await updateRationGLJ(d));
+    }
+    if(query.projectID){
+        let stateResult = await glj_calculate_facade.calculateQuantity(query,null,true);
+        return {rationID:rationID,name:stateResult.rationName,adjustState:stateResult.adjustState,ration_gljs:gljs}
+    }else {
+        throw new Error("人材机的项目ID有问题");
+    }
+
+}
+
+async function updateRationGLJ(data) {
+    let glj = data.glj;
+    let priceInfo = {
+        base_price: glj.basePrice,
+        market_price: glj.marketPrice
+    };
+    let [projcetGLJ_n,doc] = await ration_glj_facade.updateRationGLJFromDoc(glj,data.doc,priceInfo);
+    return {ID:glj.ID,doc:doc}
+
+}
+
+/*async function doRationGLJUpdate(data) {
+    let resutl = {};
+    let doc = data.doc;
+    let priceInfo = data.priceInfo;
+    let rg = await ration_glj.findOne(data.query);
+    let gljListModel = new GLJListModel();
+    let projectGLJ = getGLJSearchInfo(rg);
+    for (let key in doc) {
+        projectGLJ[key] = doc[key]
+    }
+    projectGLJ.base_price = priceInfo.base_price;
+    projectGLJ.market_price = priceInfo.market_price;
+    let projcetGLJ_n = await gljListModel.modifyGLJ(projectGLJ, rg);
+    doc.code = projcetGLJ_n.code;
+    doc.projectGLJID = projcetGLJ_n.id;
+    if (projcetGLJ_n.unit_price.is_add == 1) {
+        doc.createType = 'replace';
+        doc.rcode = projcetGLJ_n.original_code;
+    } else {
+        doc.createType = 'normal';
+        doc.rcode = '';
+    }
+    await ration_glj.findOneAndUpdate(data.query, doc);
+    //取价格
+    gljListModel.getGLJPrice(projcetGLJ_n);
+    doc.basePrice = projcetGLJ_n.unit_price.base_price;
+    doc.marketPrice = projcetGLJ_n.unit_price.market_price;
+    doc.adjustPrice = projcetGLJ_n.adjust_price;
+    doc.isAdd = projcetGLJ_n.unit_price.is_add;
+    resutl.doc = doc;
+    let stateResult = await glj_calculate_facade.calculateQuantity({
+        projectID: data.query.projectID,
+        rationID: data.query.rationID
+    },null,true);
+    resutl.adjustState = stateResult.adjustState;
+    resutl.name = stateResult.rationName;
+    return resutl;
+}*/
+
+
+async function getLibID(billsLibId,compilationId) {
+    let lib = await material_lib.findOne({"compilationId":compilationId,billsLibId:billsLibId});
+    if(lib) return lib.ID;
+    return null;
+}
+
+async function getBills(code,libID) {
+    let bills = await replace_bills.findOne({code:code,libID:libID});
+    if(bills) return bills;
+    return null;
+}
+
+async  function getMaterialByBillsID(billsItemID) {
+    return await replace_material.find({billsItemID:billsItemID},['code','name','specs','type','unit']);
+}

+ 2 - 2
modules/main/routes/material_replace_route.js

@@ -9,8 +9,8 @@ module.exports = function (app) {
 
     var materialRouter = express.Router();
 
-    materialRouter.post('/getMaterial', materialController.findMaterial);
-
+    materialRouter.post('/getMaterial', materialController.action);
+    materialRouter.post('/replace', materialController.action);//材料替换,其实是材料修改
 
     app.use('/material',materialRouter);
 }

+ 4 - 4
modules/main/routes/ration_route.js

@@ -9,10 +9,10 @@ module.exports = function (app) {
     rationRouter.post('/getData', rationController.getData);
     rationRouter.post('/getItemTemplate', rationController.getItemTemplate);
     rationRouter.post('/allocIDs', rationController.allocIDs);
-    rationRouter.post('/insertGLJAsRation', rationController.insertGLJAsRation);
-    rationRouter.post('/replaceRations', rationController.replaceRations);
-    rationRouter.post('/addNewRation', rationController.addNewRation);
-    rationRouter.post('/addMultiRation', rationController.addMultiRation);
+    rationRouter.post('/insertGLJAsRation', rationController.action);
+    rationRouter.post('/replaceRations', rationController.action);
+    rationRouter.post('/addNewRation', rationController.action);
+    rationRouter.post('/addMultiRation', rationController.action);
 
     app.use('/ration', rationRouter);
 };

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

@@ -36,7 +36,7 @@ async function calculateQuantity(query,noNeedCal,refreshRationName = false){
              glj_result:[],
              rationID:query.rationID
          };
-         let impactRation = await ration.findOne({projectID:query.projectID,ID:query.rationID,deleteInfo:null});
+         let impactRation = await ration.findOne({ID:query.rationID,projectID:query.projectID});
          let gljList = await ration_glj.find(query);//{projectID:query.projectID,rationID:query.rationID}
          let coeList = await ration_coe.find({projectID:query.projectID,rationID:query.rationID}).sort('seq').exec();
          let assList=[];

+ 14 - 7
modules/ration_glj/facade/ration_glj_facade.js

@@ -44,7 +44,8 @@ module.exports = {
     getRationTypeGLJQuantity:getRationTypeGLJQuantity,
     getInfoFromProjectGLJ:getInfoFromProjectGLJ,
     createNewRecord:createNewRecord,
-    getGLJSearchInfo:getGLJSearchInfo
+    getGLJSearchInfo:getGLJSearchInfo,
+    updateRationGLJFromDoc:updateRationGLJFromDoc
 }
 
 let operationMap = {
@@ -694,11 +695,7 @@ async function updateRationGLJByEdit(data) {
     return result;
 }
 
-async function doRationGLJUpdate(data) {
-    let resutl = {};
-    let doc = data.doc;
-    let priceInfo = data.priceInfo;
-    let rg = await ration_glj.findOne(data.query);
+async function updateRationGLJFromDoc(rg,doc,priceInfo) {
     let gljListModel = new GLJListModel();
     let projectGLJ = getGLJSearchInfo(rg);
     for (let key in doc) {
@@ -716,8 +713,18 @@ async function doRationGLJUpdate(data) {
         doc.createType = 'normal';
         doc.rcode = '';
     }
-    await ration_glj.findOneAndUpdate(data.query, doc);
+    await ration_glj.findOneAndUpdate({ID:rg.ID}, doc);
+    return [projcetGLJ_n,doc]
+}
+
+
+async function doRationGLJUpdate(data) {
+    let resutl = {};
+    let priceInfo = data.priceInfo;
+    let rg = await ration_glj.findOne(data.query);
+    let [projcetGLJ_n,doc] = await updateRationGLJFromDoc(rg,data.doc,priceInfo);
     //取价格
+    let gljListModel = new GLJListModel();
     gljListModel.getGLJPrice(projcetGLJ_n);
     doc.basePrice = projcetGLJ_n.unit_price.base_price;
     doc.marketPrice = projcetGLJ_n.unit_price.market_price;

+ 3 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -386,6 +386,9 @@ var TREE_SHEET_HELPER = {
                 TREE_SHEET_HELPER.showTipsDiv(tag,setting,hitinfo);
             }
         };
+        TreeNodeCellType.prototype.processMouseMove = function(hitinfo){
+            //console.log(hitinfo);
+        };
         TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
             let me = TREE_SHEET_HELPER;
             TREE_SHEET_HELPER.tipDiv = 'hide';

+ 113 - 11
web/building_saas/main/js/controllers/material_controller.js

@@ -2,19 +2,121 @@
  * Created by zhang on 2018/9/12.
  */
 let MaterialController = {
-    rule1:"材质及规格:",
-    replaceMaterial:function(node){
-
-        this.getMaterial([node]);
+    //规则相关映射
+    rule1: function (node) {
         let itemText = node.data.itemCharacterText;
-        let keyWord =  this.getKeyString(itemText,this.rule1);
-        console.log(keyWord);
+        let name = this.getKeyString(itemText,"材质及规格:");
+        if(name){
+            return{name:name}
+        }
+        return null;
+    },
+    rule2:function (node) {
+        let itemText = node.data.itemCharacterText;
+        let name = this.getKeyString(itemText,"混凝土种类:");
+        let specs = this.getKeyString(itemText,"混凝土强度等级:");
+        if(name||specs){
+            let doc ={};
+            if(name) doc["name"] = name;
+            if(specs) doc["specs"] = specs;
+            return doc;
+        }
+        return null
+    },
+    replaceMaterial:function(nodes){
+        let me = this;
+        this.getMaterial(nodes,function (result) {
+            if(!_.isEmpty(result)){
+                me.startReplace(nodes,result);
+            }
+        });
+    },
 
+    startReplace:function (nodes,result) {//其实应该是批量修改工料机属性,与替换工料机不同
+        let me = this,updateData = [];
+        for(let n of nodes){
+            let code = n.data.code;
+            if(code.length >= 9){
+                let r_list = this.eachNode(n,result[code.substr(0,9)]);
+                if(r_list.length > 0) updateData.push(...r_list);
+            }
+        }
+        if(updateData.length == 0) return;
+        $.bootstrapLoading.start();
+        CommonAjax.post("/material/replace",updateData,function(result){
+            $.bootstrapLoading.end();
+            me.updateCacheAfterReplace(result)
+        })
     },
 
+    updateCacheAfterReplace:function (result){
+        let nodes = [];
+        for(let data of result){
+            let node = projectObj.project.ration_glj.refreshRationNode(data.name,data.adjustState,data.rationID);//刷新定额名称和子目调整状态
+            if(node) nodes.push(node);
+            if(data.ration_gljs.length > 0) this.refreshRationGLJ(data.ration_gljs);
+        }
+        if(nodes.length >0){
+            projectObj.project.projectGLJ.loadData(function () {//先加载项目工料机
+                projectObj.project.calcProgram.calcNodesAndSave(nodes,function(){
+                    installationFeeObj.calcInstallationFee();
+                });
+                gljOprObj.refreshView();
+            })
+        }
+    },
+    refreshRationGLJ:function(ration_gljs){
+        let ration_glj_model = projectObj.project.ration_glj;
+        for(let rg of ration_gljs){
+             let glj = ration_glj_model.refreshByID(rg.ID,rg.doc);
+            ration_glj_model.refreshTreeNodeIfNeeded(glj);//刷新造价书上的树节点(如果需要)
+        }
+    },
+
+    eachNode:function (node,item) {
+        let replaceDatas =[];
+        if(item && item.bills.rule){
+             let replace_property = this["rule"+item.bills.rule](node);//按清单设置的规则获取要修改的属性
+             if(replace_property){
+                 replaceDatas = this.getReplaceData(node.data.ID,item.materialMap,replace_property);
+             }
+        }
+        return replaceDatas;
+    },
+
+    getReplaceData:function (billsItemID,materialMap,replace_property) {
+        let list = [];
+        let replace_glj_list = this.findMatchRationGLJ(billsItemID,materialMap);//取出需要替换的工料机和对替换的材料内容
+        for(let r of replace_glj_list){
+            let doc = this.getDoc(r.glj,r.material,replace_property);//获取要修改的字段
+            list.push({glj:gljOprObj.setGLJPrice(r.glj),doc:doc});
+        }
+        return list;
+    },
 
 
+    getDoc:function (glj,material,replace_property) {//取定额工料机中需要修改的内容
+        let doc = {},keyList = ['name','specs','type','unit'];
+        for(let key of keyList){
+            if(glj[key] != material[key]) doc[key] = material[key];
+        }
+        for(let rkey in replace_property){
+            doc[rkey] = replace_property[rkey]
+        }
+        return doc;
+
+    },
 
+
+    findMatchRationGLJ:function (billsItemID,materialMap) {//查找清单下匹配的需要替换的定额工料机
+        let replaceList=[];
+        for(let g of projectObj.project.ration_glj.datas){
+            if(g.billsItemID == billsItemID && materialMap[g.original_code]) {
+                replaceList.push({glj:g,material:materialMap[g.original_code]});
+            }
+        }
+        return replaceList;
+    },
     getMaterial:function (nodes,callback) {
         let data = [],materialMap= null;
         for(let n of nodes){
@@ -25,11 +127,11 @@ let MaterialController = {
             }
         }
         if(data.length>0){
-            //data去重
-
-
-
-
+            //data 按编码去重
+            let dataMap = _.indexBy(data,'code');
+            CommonAjax.post("/material/getMaterial",dataMap,function (result) {
+                callback(result);
+            })
         }else {
             callback(null);
         }

+ 20 - 19
web/building_saas/main/js/models/ration_glj.js

@@ -242,18 +242,19 @@ let ration_glj = {
             this.reCalcWhenGLJChange({rationID:rationID});
         };
         ration_glj.prototype.refreshEachItme = function (doc, query) {
+            let glj = this.refreshByID(query.ID,doc);
+            return glj.rationID;
+        };
+
+        ration_glj.prototype.refreshByID=function (ID,doc) {
             let glj_list = projectObj.project.ration_glj.datas;
-            let glj_index = _.findIndex(glj_list, (glj) => {
-                return glj.ID == query.ID;
-            })
-            /*var sheet_index= _.findIndex(gljOprObj.sheetData,(sd)=>{
-             return sd.ID==query.ID;
-             })*/
+            let glj_index = _.findIndex(glj_list,{"ID":ID});
             _.forEach(doc, function (n, key) {
                 glj_list[glj_index][key] = n;
             });
-            return glj_list[glj_index].rationID;
+            return glj_list[glj_index]
         };
+
         ration_glj.prototype.refreshAfterDelete = function (data) {
             let me = projectObj.project.ration_glj;
             let glj_list = me.datas;
@@ -476,22 +477,22 @@ let ration_glj = {
         };
         ration_glj.prototype.refreshRationAfterEdit= function(data,rationID,rnode){
             let nodes = [];
+            let node = this.refreshRationNode(data.name,data.adjustState,rationID);
+            if (node) nodes.push(node);
+            if (rnode)  nodes.push(rnode);
+            projectObj.mainController.refreshTreeNode(nodes);
+        };
+        ration_glj.prototype.refreshRationNode = function(name,adjustState,rationID){
             let node = projectObj.project.mainTree.findNode(rationID);
-            if (node) {
-                if(data.adjustState){
-                    node.data.adjustState = data.adjustState;
-                }
-                if(data.name){
-                    node.data.name = data.name;
-                }
-                nodes.push(node);
+            if (!node)  return null;
+            if(gljUtil.isDef(adjustState)){
+                node.data.adjustState = adjustState;
             }
-            if (rnode) {
-                nodes.push(rnode);
+            if(gljUtil.isDef(name)){
+                node.data.name = name;
             }
-            projectObj.mainController.refreshTreeNode(nodes);
+           return node
         };
-
         ration_glj.prototype.getGLJData = function (cb) {
             let engineerID = projectInfoObj.projectInfo.property.engineering_id;
             CommonAjax.get('/rationGlj/getGLJData/'+engineerID, function (data) {

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

@@ -1005,15 +1005,13 @@ $(function(){
 
     $('#calcBaseFeeRate').on('shown.bs.modal', function (e) {
         let toggle = $('#calcBaseFeeRateConf').attr('toggle');
-        if(toggle == 'feeRate'){
-            if(feeRateObject.feeRateSpreads==null){
-                feeRateObject.createSheet();
-            }
-            feeRateObject.feeRateSelection=null;
-            feeRateObject.showFeeRateTree(feeRateObject.feeRateSheet,feeRateObject.sheetSetting,projectObj.project.FeeRate.getActivateFeeRate().rates);
-            feeRateObject.locate();
-            feeRateObject.feeRateSpreads.refresh();
+        if(feeRateObject.feeRateSpreads==null){
+            feeRateObject.createSheet();
         }
+        feeRateObject.feeRateSelection=null;
+        feeRateObject.showFeeRateTree(feeRateObject.feeRateSheet,feeRateObject.sheetSetting,projectObj.project.FeeRate.getActivateFeeRate().rates);
+        feeRateObject.locate();
+        feeRateObject.feeRateSpreads.refresh();
     });
     $('#tabFeeRate').on('shown.bs.tab', function () {
         if(feeRateObject.feeRateSpreads){

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

@@ -1404,7 +1404,7 @@ var gljOprObj = {
         }else {
             hasCom = this.hasComposition(node.data);
         }
-        return hasCom|| node.data.isEstimate == 1;
+        return hasCom;//2018-9-14 需求变更暂估工料机也能修改市场价原语句:return hasCom|| node.data.isEstimate == 1
     },
     locateZTree: function(ID) {
         let zTree = $.fn.zTree.getZTreeObj("gljTree");

+ 13 - 9
web/building_saas/main/js/views/project_view.js

@@ -1087,6 +1087,7 @@ var projectObj = {
         var project = this.project, spread = this.mainSpread, controller = this.mainController;
         $.contextMenu({
             selector: '#billsSpread',
+            selectableSubMenu: true,
             build: function ($trigger, e) {
                 var target = SheetDataHelper.safeRightClickSelection($trigger, e, spread);
                 controller.setTreeSelected(controller.tree.items[target.row]);
@@ -1231,13 +1232,16 @@ var projectObj = {
                     callback: function (key, opt) {
                         project.Ration.addNewRation(null,rationType.volumePrice,null,true);
                        // ProjectController.addRation(project, controller, rationType.volumePrice);
-                    }/*,
-                    visible: function(key, opt){
-                        var selected = project.mainTree.selected;
-                        if(selected){
-                           return canInsertRationNode(selected);
+                    },
+                  /*  items:{
+                        firstCommand:{
+                            name: "插入量价",
+                            icon: 'fa-sign-in',
+                            callback:function(key){
+
+                            }
                         }
-                       return false;
+
                     }*/
                 },
                 "insertGLJ": {
@@ -1387,12 +1391,12 @@ var projectObj = {
                 "replaceMaterial":{
                     name:'智能材料替换',
                     icon: 'fa-edit',
-                    visible:function (key,opt) {
+                    disabled:function (key,opt) {
                         let  selected = project.mainTree.selected;
-                        return selected.sourceType==ModuleNames.bills ?project.Bills.isFXorBX(selected)||selected.source.children.length ==0:false//是分项、补项或叶子清单才显示;
+                        return selected.sourceType==ModuleNames.bills ?!(project.Bills.isFXorBX(selected)||selected.source.children.length ==0):true//是分项、补项或叶子清单才有效;
                     },
                     callback:function(){
-                        MaterialController.replaceMaterial(project.mainTree.selected);
+                        MaterialController.replaceMaterial([project.mainTree.selected]);
                     }
                 }
             }