Browse Source

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost into 1.0.0_online

zhongzewei 7 years ago
parent
commit
25b0c8b670

+ 1 - 0
config/gulpConfig.js

@@ -119,6 +119,7 @@ module.exports = {
         'web/building_saas/main/js/main.js',
         'web/building_saas/main/js/controllers/project_controller.js',
         'web/building_saas/main/js/controllers/block_controller.js',
+        'web/building_saas/main/js/controllers/material_controller.js',
         'web/building_saas/main/js/views/side_tools.js',
         'web/building_saas/main/js/views/std_billsGuidance_lib.js',
         'web/building_saas/main/js/views/std_bills_lib.js',

+ 53 - 0
modules/all_models/material_replace_lib.js

@@ -0,0 +1,53 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+//材料替换库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const material_lib = new Schema({
+        ID:{type:String,index:true},
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        compilationId: String,
+        compilationName: String,
+        billsLibId:Number,
+        billsLibName:String,
+        deleted: Boolean
+    }, {versionKey: false}
+);
+
+mongoose.model("std_material_replace_lib", material_lib,"std_material_replace_lib");
+
+
+const std_replace_bills = new Schema({
+        ID: {type:String,index:true},
+        libID:{type:String,index:true},
+        code: {type:String,index:true},
+        name: String,
+        rule:Number//规则类型
+    }, {versionKey: false}
+);
+
+mongoose.model('std_replace_bills', std_replace_bills, 'std_replace_bills');
+
+
+const std_replace_material = new Schema({
+    ID: {type:String,index:true},
+    libID:{type:String,index:true},
+    billsItemID:{type:String,index:true},
+    code: String,
+    name: String,
+    specs: String,
+    type: Number,
+    unit: String
+},{versionKey: false});
+
+mongoose.model('std_replace_material', std_replace_material, 'std_replace_material');
+
+
+
+
+

+ 29 - 28
modules/common/const/glj_type_const.js

@@ -7,34 +7,35 @@
  */
 
 const gljType = {
-    // 人工
-    LABOUR: 1,
-    // ==============材料类型=================
-    // 普通材料
-    GENERAL_MATERIAL: 201,
-    // 混凝土
-    CONCRETE: 202,
-    // 砂浆
-    MORTAR: 203,
-    // 配合比
-    MIX_RATIO: 204,
-    // 商品混凝土
-    COMMERCIAL_CONCRETE: 205,
-    // 商品砂浆
-    COMMERCIAL_MORTAR: 206,
-    // ==============材料类型=================
-    // ==============机械类型=================
-    // 普通机械
-    GENERAL_MACHINE: 301,
-    // 机械组成物
-    MACHINE_COMPOSITION: 302,
-    // 机上人工
-    MACHINE_LABOUR: 303,
-    // ==============机械类型=================
-    // 主材
-    MAIN_MATERIAL: 4,
-    // 设备
-    EQUIPMENT: 5
+    LABOUR: 1,                                  // 人工
+    // ==============材料类型 ↓=================
+    GENERAL_MATERIAL: 201,                      // 普通材料
+    CONCRETE: 202,                              // 混凝土
+    MORTAR: 203,                                // 砂浆
+    MIX_RATIO: 204,                             // 配合比
+    COMMERCIAL_CONCRETE: 205,                   // 商品混凝土
+    COMMERCIAL_MORTAR: 206,                     // 商品砂浆
+    OTHER_MATERIAL: 207,                        // 其它材料
+    // ==============材料类型 ↑=================
+    // ==============机械类型 ↓=================
+    GENERAL_MACHINE: 301,                       // 机械台班
+    MACHINE_COMPOSITION: 302,                   // 机械组成物
+    MACHINE_LABOUR: 303,                        // 机上人工
+    INSTRUMENT: 304,                            // 仪器仪表
+    FUEL_POWER_FEE:305,                         // 燃料动力费
+    DEPRECIATION_FEE:306,                       // 折旧费
+    INSPECTION_FEE:307,                         // 检修费
+    MAINTENANCE:308,                            // 维护费
+    DISMANTLING_FREIGHT_FEE:309,                // 安拆费及场外运费
+    VERIFICATION_FEE:310,                       // 校验费
+    OTHER_FEE:311,                              // 其他费用
+    OTHER_MACHINE_USED:312,                     // 其他施工机具使用费
+    // ==============机械类型 ↑=================
+    MAIN_MATERIAL: 4,                           // 主材
+    EQUIPMENT: 5,                               // 设备
+    MANAGEMENT_FEE: 6,                          // 企业管理费
+    PROFIT: 7,                                  // 利润
+    GENERAL_RISK_FEE: 8                         // 一般风险费
 };
 
 export default gljType;

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

@@ -38,7 +38,7 @@ class GLJListModel extends BaseModel {
      * @var {Array}
      */
     ownCompositionTypes = [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,
-        GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL];
+        GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL,GLJTypeConst.INSTRUMENT];
 
     /**
      * 构造函数

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

@@ -0,0 +1,34 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+
+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 ={
+    action:async function(req,res){//自动跳转到URL对应的controller方法
+        let result={
+            error:0
+        };
+        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;
+        }
+        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);
 
 
-}

+ 3 - 1
modules/main/facade/bill_facade.js

@@ -221,10 +221,12 @@ function generateBillTasks(data) {
 
 
 async function insertMany(datas,model) {
+    let tem = [];
     while (datas.length>1000){//因为mongoose限制了批量插入的条数为1000.所以超出限制后需要分批插入
         let newList = datas.splice(0,1000);//一次插入1000条
         await model.insertMany(newList);
+        tem = tem.concat(newList);
     }
     await model.insertMany(datas);
-
+    if(tem.length > 0) datas.push(...tem);//还原数组
 }

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

@@ -0,0 +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']);
+}

+ 16 - 0
modules/main/routes/material_replace_route.js

@@ -0,0 +1,16 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+
+let express = require('express');
+let materialController = require('../controllers/material_replace_controller');
+
+module.exports = function (app) {
+
+    var materialRouter = express.Router();
+
+    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;

+ 37 - 20
public/web/tree_sheet/tree_sheet_helper.js

@@ -125,7 +125,7 @@ var TREE_SHEET_HELPER = {
                 }
             }
             setting.cols.forEach(function (colSetting, iCol) {
-                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
+
    /* if(typeof projectObj !== 'undefined'){ 7/28  取消黑体显示
                     let boldFontStyle = projectObj.getBoldFontStyle(node, colSetting);
                     sheet.setStyle(iRow, iCol, boldFontStyle);
@@ -179,6 +179,8 @@ var TREE_SHEET_HELPER = {
 
                 }
 
+                if(colSetting.visible == false) return;//隐藏列不做其它操作
+                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
                 if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
                 } else {
@@ -377,21 +379,18 @@ var TREE_SHEET_HELPER = {
                 hitinfo.sheet.repaint();
             }
         };
-        TreeNodeCellType.prototype.processMouseEnter = function(hitinfo){
-            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
-            let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
-            if(tag&&tag!=''){
-                TREE_SHEET_HELPER.showTipsDiv(tag,setting,hitinfo);
+        TreeNodeCellType.prototype.processMouseMove = function(hitinfo){//造价书主界面,当鼠标移动到单元格最右往左50个像素内时才显示悬浮提示内容
+            if (hitinfo.sheet.name()!=="mainSheet") return;
+            let offset = 20;//从右向左显示的像素范围
+            let leftX = hitinfo.cellRect.x + hitinfo.cellRect.width;//最右边的坐标
+            if(leftX - hitinfo.x <= offset){//如果鼠标移动到的位置是在显示的范围内显示悬浮提示
+                TREE_SHEET_HELPER.delayShowTips(hitinfo,setting);
+            }else {//如果移出了范围,隐藏悬浮提示
+                TREE_SHEET_HELPER.hideTipsDiv();
             }
         };
         TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
-            let me = TREE_SHEET_HELPER;
-            TREE_SHEET_HELPER.tipDiv = 'hide';
-            if (me._toolTipElement) {
-                $(me._toolTipElement).hide();
-                me._toolTipElement = null;
-            };
-            TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
+            TREE_SHEET_HELPER.hideTipsDiv();
         };
 
         let TipCellType = function () {};
@@ -444,13 +443,7 @@ var TREE_SHEET_HELPER = {
             TREE_SHEET_HELPER.showTipsDiv(text,setting,hitinfo);
         };
         TipCellType.prototype.processMouseLeave = function (hitinfo) {
-            let me = TREE_SHEET_HELPER;
-            TREE_SHEET_HELPER.tipDiv = 'hide';
-            if (me._toolTipElement) {
-                $(me._toolTipElement).hide();
-                me._toolTipElement = null;
-            };
-            TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
+            TREE_SHEET_HELPER.hideTipsDiv();
         }
 
         TREE_SHEET_HELPER.protectdSheet(sheet);
@@ -513,6 +506,16 @@ var TREE_SHEET_HELPER = {
             }
         }
     },
+    hideTipsDiv:function () {
+        TREE_SHEET_HELPER.tipTimeStamp = +new Date();//这个是为了造价书清单编号树节点的那个延时显示而打的时间戳,防止已经要隐藏的提示框,延时显示
+        let me = TREE_SHEET_HELPER;
+        TREE_SHEET_HELPER.tipDiv = 'hide';
+        if (me._toolTipElement) {
+            $(me._toolTipElement).hide();
+            me._toolTipElement = null;
+        }
+        TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
+    },
     tipDivCheck(){
         setTimeout(function () {
             let tips = $('#autoTip');
@@ -523,5 +526,19 @@ var TREE_SHEET_HELPER = {
                 TREE_SHEET_HELPER._toolTipElement = null;
             }
         },600)
+    },
+    delayShowTips:function(hitinfo,setting){//延时显示
+        let delayTimes = 500; //延时时间
+        let now_timeStamp = +new Date();
+        TREE_SHEET_HELPER.tipTimeStamp = now_timeStamp;
+        setTimeout(function () {
+            if(now_timeStamp - TREE_SHEET_HELPER.tipTimeStamp == 0){//鼠标停下的时候才显示
+                let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+                let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
+                if(tag&&tag!=''){
+                    TREE_SHEET_HELPER.showTipsDiv(tag,setting,hitinfo);
+                }
+            }
+        },delayTimes);
     }
 };

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

@@ -31,8 +31,6 @@
         let userAccount = '<%- userAccount %>';
         let userID = '<%- userID %>';
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
-        console.log(`projectReadOnly`);
-        console.log(projectReadOnly);
     </script>
 </head>
 
@@ -1547,6 +1545,7 @@
     <script type="text/javascript" src="/web/building_saas/main/js/main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/controllers/project_controller.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/controllers/block_controller.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/controllers/material_controller.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/side_tools.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/std_billsGuidance_lib.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/std_bills_lib.js"></script>
@@ -1598,11 +1597,6 @@
         </script>
 
         <SCRIPT type="text/javascript">
-            let test = [{a: '1', b:'2'}, {t:{tt:'t',n: 'n'}}];
-            let clT = _.cloneDeep(test);
-            clT[0].a = '2222';
-            console.log(test);
-            console.log(clT);
             let clearFlag = false;
             function onCheck(e, treeId, treeNode) {
                 count();

+ 0 - 1
web/building_saas/main/js/controllers/block_controller.js

@@ -331,7 +331,6 @@ let BlockController = {
                 i==0?firstNode = temNode:'';
             }
         }
-
         ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes);
         let sels = projectObj.mainController.sheet.getSelections();
         //设置选中并更新下方显示

+ 154 - 0
web/building_saas/main/js/controllers/material_controller.js

@@ -0,0 +1,154 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+let MaterialController = {
+    //规则相关映射
+    rule1: function (node) {
+        let itemText = node.data.itemCharacterText;
+        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){
+            let code = n.data.code;
+            if(code.length >= 9 && n.data.billsLibId){
+                let billCode = code.substr(0,9);
+                data.push({code:billCode,billsLibId:n.data.billsLibId});
+            }
+        }
+        if(data.length>0){
+            //data 按编码去重
+            let dataMap = _.indexBy(data,'code');
+            CommonAjax.post("/material/getMaterial",dataMap,function (result) {
+                callback(result);
+            })
+        }else {
+            callback(null);
+        }
+    },
+
+    getKeyString:function (itemText,matchStr) {//截取关键数据
+        itemText = itemText.replace(/:/g, ":");//中文字符转换为英文字符
+        itemText = itemText.replace(matchStr,"@$@");//用特殊符号取代关键字,方便截取
+        let index = itemText.indexOf("@$@");
+        if(index == -1) return null;
+        let temString = itemText.substr(index+3);
+        let strArray =  temString.split(/\n/);
+        let keyString = this.trim(strArray[0]);
+        return keyString===""?null:keyString;
+    },
+    trim:function (str) {
+        return str.replace(/(^\s*)|(\s*$)/g, "");
+    }
+
+};

+ 7 - 4
web/building_saas/main/js/controllers/project_controller.js

@@ -29,15 +29,18 @@ ProjectController = {
                 }
                 return rst;
             });
+            let lastNode = null;
             for(let newNode of newNodes){
                 sc.sheet.addRows(newNode.serialNo(), 1);
-            }
-            for(let newNode of newNodes){
-                sc.setTreeSelected(newNode);
                 TREE_SHEET_HELPER.refreshTreeNodeData(sc.setting, sc.sheet, [newNode], false);
-                sc.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
+                lastNode = newNode
                // sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
             }
+            if(lastNode){
+                sc.setTreeSelected(lastNode);
+                sc.sheet.setSelection(lastNode.serialNo(), sels[0].col, 1, 1);
+            }
+
             cbTools.refreshFormulaNodes();
         });
     },

+ 13 - 9
web/building_saas/main/js/models/calc_program.js

@@ -366,7 +366,9 @@ let calcTools = {
 
         if (priceType == priceTypes.ptDiffPrice){
             if (typeof isCQ2018 != 'undefined'){
-                result = (temp - temp2).toDecimal(decimalObj.ration.unitPrice)    // 重庆2018所有都是先汇总相减后再取舍
+                // 如下这一句十分重要!JS计算误差导致379.08-331.695=47.38499999999999。如果直接取2位会变成47.38。所以先取6位47.385,再取2位47.39。
+                result = (temp - temp2).toDecimal(decimalObj.process);
+                result = result.toDecimal(decimalObj.ration.unitPrice)    // 重庆2018所有都是先汇总相减后再取舍
             }
             else{
                 if (gljTypes == baseMaterialTypes)
@@ -388,7 +390,7 @@ let calcTools = {
         for (let glj of gljArr) {
             if (baseMachineMasterTypes.includes(glj.type)){
                 // 机型不符
-                if ((masterTypeFilter.length > 0) && (glj.model && !masterTypeFilter.includes(glj.model))) break;
+                if ((masterTypeFilter.length > 0) && (glj.model && !masterTypeFilter.includes(glj.model))) continue;
 
                 let gljQ;
                 if (isTender){
@@ -409,9 +411,10 @@ let calcTools = {
                         mdSum = (mdSum).toDecimal(decimalObj.glj.unitPriceHasMix);
                     }
                 }
-                // result = result + (gljQ * mdSum).toDecimal(decimalObj.process);
-                result = result + (gljQ * mdSum).toDecimal(decimalObj.ration.unitPrice);
-                result = (result).toDecimal(decimalObj.ration.unitPrice);
+                if (typeof isCQ2018 != 'undefined')
+                    result = (result + (gljQ * mdSum).toDecimal(decimalObj.process)).toDecimal(decimalObj.process)
+                else
+                    result = (result + (gljQ * mdSum).toDecimal(decimalObj.ration.unitPrice)).toDecimal(decimalObj.ration.unitPrice);
             }
         }
         result = (result).toDecimal(decimalObj.ration.unitPrice);
@@ -884,13 +887,14 @@ let calcTools = {
                 let gljQ;
                 if (isTender){
                     calcTools.calcGLJTenderQty(node, glj);
-                    gljQ = glj.tenderQuantity;
+                    gljQ = glj.tenderQuantity.toDecimal(decimalObj.glj.quantity);
                 }
                 else
-                    gljQ = glj.quantity;
+                    gljQ = glj.quantity.toDecimal(decimalObj.glj.quantity);
 
-                rst = rst + (gljQ * calcTools.uiNodeQty(node)).toDecimal(decimalObj.process);
-                rst = rst.toDecimal(decimalObj.process);
+                // rst = rst + (gljQ * calcTools.uiNodeQty(node)).toDecimal(decimalObj.process);
+                // rst = rst.toDecimal(decimalObj.process);
+                rst = (rst + gljQ).toDecimal(decimalObj.process);
             }
         };
         return rst.toDecimal(decimalObj.glj.quantity);

+ 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) {

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

@@ -201,8 +201,9 @@ var feeRateObject={
         let rates = projectObj.project.FeeRate.getActivateFeeRate().rates;
         let rowIdx = 0, pID = 0;
         if (fID){
+            fID = parseInt(fID);
             rowIdx = _.findIndex(rates,{ID:fID});
-            pID = rates[rowIdx].ParentID;
+            if(rowIdx != -1) pID = rates[rowIdx].ParentID;
         }
         // 费率现有可能有多层节点,所以要递归展开父节点
         if(pID) expandParent(pID,rates,sheet);
@@ -819,9 +820,10 @@ var feeRateObject={
     submitFeeRateFromBill:function () {
        var rate = feeRateObject.feeRateSelection;
        var selected = projectObj.project.mainTree.selected;
+       if(selected.data.feeRateID === parseInt(rate.ID)) return $("#calcBaseFeeRate").modal('hide');
         $.bootstrapLoading.start();
         projectObj.project.FeeRate.submitFeeRateFromBill(rate,selected.data,function (data) {
-            selected.data.feeRateID=rate.ID.toString();
+            selected.data.feeRateID= parseInt(rate.ID);
             selected.data.feeRate=scMathUtil.roundToString(rate.rate,getDecimal("feeRate"));
             selected.changed = true;
             projectObj.project.calcProgram.calcAndSave(selected);
@@ -1005,15 +1007,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");

+ 2 - 2
web/building_saas/main/js/views/main_tree_col.js

@@ -54,8 +54,8 @@ let MainTreeCol = {
             else
                 rst = isDef(node.data.code) ? node.data.code : '';
 
-/*            if (node.data.adjustState && rst != '')
-                rst = rst + rationPrefix.replace;*/
+            if (node.data.adjustState && rst != '')
+                rst = rst + rationPrefix.replace;
             return rst;
         },
         marketPrice:function (node) {

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

@@ -540,6 +540,7 @@ var projectObj = {
             if (isDef(node.data.prefix) && node.data.prefix !== rationPrefix.none){
                  value = value.replace(new RegExp(node.data.prefix), '');
             };
+            value = value.replace(new RegExp(rationPrefix.replace), '');
             info.sheet.setValue(info.row, info.col, value);
         }
         if(node&&fieldName =='quantity'&&(node.data.quantityEXP !==null||node.data.quantityEXP !==undefined)){
@@ -662,7 +663,7 @@ var projectObj = {
                         curNode = projectObj.project.mainTree.items[i - 1];
                         break;
                     }
-                };
+                }
 
                 if (nodesArr.length < count){
                     if (projectObj.project.mainTree.selected != curNode)
@@ -708,7 +709,7 @@ var projectObj = {
                         // 编号去掉“换、借、补”等多余的字
                         code = code.replace(new RegExp(rationPrefix.complementary), '');
                         code = code.replace(new RegExp(rationPrefix.borrow), '');
-                        // code = code.replace(new RegExp(rationPrefix.replace), '');
+                        code = code.replace(new RegExp(rationPrefix.replace), '');
                         updateRationCodes.push({'node':ptNode, value:code});
                     }
                     projectObj.project.Ration.updateRationCodes(updateRationCodes);
@@ -771,7 +772,7 @@ var projectObj = {
             for (let changedCell of changedObj.changedCells) {
                 let node = project.mainTree.items[changedCell.row];
                 let colSetting = setting.cols[changedCell.col];
-                let value = projectObj.checkSpreadEditingText(changedCell.text, colSetting)
+                let value = projectObj.checkSpreadEditingText(changedCell.text, colSetting);
                 if(colSetting.data.field=='code' && node.sourceType == project.Ration.getSourceType()&&node.data.type==rationType.ration){//如果是更新定额的编码
                     updateRationCodes.push({'node':node,value:value});
                 }else {
@@ -1087,6 +1088,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 +1233,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": {
@@ -1383,6 +1388,17 @@ var projectObj = {
                             projectObj.editContent(node,'claimVisa');
                         }
                     }
+                },
+                "replaceMaterial":{
+                    name:'智能材料替换',
+                    icon: 'fa-edit',
+                    disabled:function (key,opt) {
+                        let  selected = project.mainTree.selected;
+                        return selected.sourceType==ModuleNames.bills ?!(project.Bills.isFXorBX(selected)||selected.source.children.length ==0):true//是分项、补项或叶子清单才有效;
+                    },
+                    callback:function(){
+                        MaterialController.replaceMaterial([project.mainTree.selected]);
+                    }
                 }
             }
         });
@@ -1405,6 +1421,7 @@ var projectObj = {
         col = parseInt(col);
         const sheet = this.mainSpread.getActiveSheet();
         sheet.setSelection(row, col, 1, 1);
+        row=row<this.mainController.tree.items.length?row:0;
         this.mainController.setTreeSelected(this.mainController.tree.items[row]);//触发树节点选中事件
         sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
     },
@@ -1693,10 +1710,12 @@ var projectObj = {
         });
     },
     ifItemCharHiden:function (setting) {//项目特征及内容列是否隐藏
-        let col = _.find(setting.cols,function (item) {
-            return  item.data.field == "itemCharacterText";
-        })
-        return !col.visible;
+        if(this.itemCol == null||this.itemCol == undefined){
+            this.itemCol = _.find(setting.cols,function (item) {
+                return  item.data.field == "itemCharacterText";
+            })
+        }
+        return !this.itemCol.visible;
     },
     //综合合价cellType
     getCommonTotalFeeCellType:function () {
@@ -2783,12 +2802,12 @@ $('#calcBaseFeeRateConf').click(function () {
         selected.data.userCalcBase = calcBaseValue;
         projectObj.project.calcBase.calculate(selected);
     }
-    if(!projectObj.project.calcBase.success){
-        return;
-    }
     if(validateFeeRate){
         feeRateObject.submitFeeRateFromBill();
     }
+    if(!projectObj.project.calcBase.success){
+        return;
+    }
     else if(!validateFeeRate && needToSave) {
         projectObj.project.calcProgram.calcAndSave(selected);
     }

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

@@ -127,9 +127,9 @@ function overwriteRationCalcBases (taxType){
             rationCalcBases['安拆费及场外运输费'] = function (node, isTender) {
                 return calcTools.machineDetailFee(node, node.data.gljList, [], gljType.DISMANTLING_FREIGHT_FEE, isTender);
             };
-            rationCalcBases['燃料动力费'] = function (node, isTender) {
+/*            rationCalcBases['燃料动力费'] = function (node, isTender) {
                 return calcTools.machineDetailFee(node, node.data.gljList, [], gljType.FUEL_POWER_FEE, isTender);
-            };
+            };*/
             rationCalcBases['定额仪器仪表费'] = function (node, isTender) {
                 return calcTools.rationBaseFee(node, [gljType.INSTRUMENT], priceTypes.ptBasePrice, isTender);
             };