/** * Created by zhang on 2018/11/26. */ let mbzm_obj={ spread:null, nodeChanged:false, datas:[], locateMap:{ INMEASURE:1, INFBFX:2, AFTERRATION:3 }, setting:{ header: [ {headerName: "编码", headerWidth: 130, dataCode: "code", dataType: "String", formatter: "@"}, {headerName: "模板类别", headerWidth: 260, dataCode: "name", dataType: "String", hAlign: "left"}, {headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center",getText:'forUnit'}, {headerName: "系数", headerWidth: 65, dataCode: "coe", dataType: "Number",validator:"number"}, {headerName: "工程量", headerWidth: 65, dataCode: "quantity", dataType: "Number",validator:"number",getText:'forQuantity'},//这里做成当系数不为0时,动态生成工程量,同步更新太麻烦 {headerName: "关联类别", headerWidth: 100, dataCode: "type", dataType: "String"}, {headerName: "清单位置", headerWidth: 200, dataCode: "position", hAlign: "left", dataType: "String",cellType:'selectButton',getText:'forPosition'}, ], view: { lockColumns:["code","name","unit","type"], rowHeaderWidth:25 }, getText:{ forPosition:function (item) { let createL = $('#createLocation').val(); if(createL == mbzm_obj.locateMap.INMEASURE) return mbzm_obj.getDisplayText(item.billID,item.billsLocation); if(createL == mbzm_obj.locateMap.INFBFX) return mbzm_obj.getDisplayText(item.fxID,""); return "" }, forUnit:function (item) {//这里显示的单位是去掉定额单位前面的数字的结果 return item.unit &&_.isString(item.unit)?item.unit.replace(/^\d+/,""):"" }, forQuantity:function (item) { return mbzm_obj.getQuantity(item); } } }, getDisplayText:function (billID,position) { if(billID && billID!=''){ let node = projectObj.project.mainTree.getNodeByID(billID); if(node){ let code = node.data.code?node.data.code:""; let name = node.data.name?node.data.name:""; return code +" "+name; } } return position; }, //当点击应用的时候才保存数据 initSpread:function () { this.spread = SheetDataHelper.createNewSpread($("#mbzmSpread")[0]); sheetCommonObj.spreadDefaultStyle(this.spread); this.sheet = this.spread.getSheet(0); sheetCommonObj.initSheet(this.sheet, this.setting); this.sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange); this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, installationFeeObj.onPositionButtonClick);//共用一个位置选择器 this.sheet.name('ration_template'); if(projectReadOnly){ disableSpread(this.spread); } }, refresh:function () { let total = $('#mbzmSpread').parent().height(); let b_height = $('#mbzmSpread').prev('.col-12').height(); $('#mbzmSpread').css('height',total- b_height); this.spread?this.spread.refresh():this.initSpread(); }, refreshSheetData:function () { if($('#mbzmSpread').is(':visible')) sheetCommonObj.showData(this.sheet, this.setting,this.datas); }, showMBZMData:function(node){ let selected = node?node:projectObj.project.mainTree.selected; if(this.nodeChanged == true){//选中的行改变了才做初始化,刷新当前缓存, 在project_view 中treeSelectedChanged方法里设置 let datas = []; $("#createLocation").val(this.locateMap.INMEASURE);//初始化 if(selected&&selected.sourceType == ModuleNames.ration){ let ration = selected.data; let template = projectObj.project.ration_template.getTemplateByRationID(ration.ID); if(template) { $("#createLocation").val(template.createLocation); let pcol = _.findIndex(this.setting.header,{dataCode:"position"}); this.setting.header[pcol].visible = template.createLocation == this.locateMap.AFTERRATION?false:true; datas = _.cloneDeep(template.templateList); } } this.datas = datas; this.nodeChanged = false;//这里要恢复成false 应为调用gljObj.refresh() 方法也会进到这里来,这时节点应是没有改变的 } sheetCommonObj.showData(this.sheet, this.setting,this.datas); this.sheet.setRowCount(this.datas.length); }, onSheetValueChange:function (e,info) { let me = mbzm_obj; let selected = projectObj.project.mainTree.selected; let row = info.row, col = info.col; let dataCode = me.setting.header[col].dataCode; let recode = me.datas[row], value = info.newValue; if (info.newValue === undefined) { return; } if (value && !sheetCommonObj.checkData(col, me.setting, value)) { alert('输入的数据类型不对,请重新输入!'); me.refreshSheetData(); return; } if (dataCode === 'coe') {// //为了避免各种同步更新,后面的工程量改成实时动态计算,所以这里更新为0 recode["quantity"] = "0"; } if (dataCode === 'quantity') {//定额默认显示为0,可输入数值,输入数值后,则清空前面的系数列 value = scMathUtil.roundForObj(value, getDecimal('ration.quantity'))+""; recode["coe"] = "0"; } recode[dataCode] = value; me.refreshSheetData(); }, getQuantity:function(item){//当系数不为0的时候实时获取消耗量 if(item.coe && item.coe!="0"){ let selected = projectObj.project.mainTree.selected; let rationQuantity = selected.data.quantity; rationQuantity = rationQuantity?scMathUtil.roundForObj(rationQuantity, getDecimal('ration.quantity')):0; let times = parseInt(selected.data.unit); times = isNaN(times)?1:times;//工程量要乘以定额单位的倍数 let value = scMathUtil.roundForObj(item.coe, getDecimal('process')); //为了避免各种同步更新这里改成实时动态计算带系数的工程量 return scMathUtil.roundForObj(rationQuantity * value*times, getDecimal('ration.quantity'))+""; }else { return item.quantity; } }, updatePosition:function (recode) { let selection = this.sheet.getSelections()[0]; let selectedItem =this.datas[selection.row]; let updateField = $("#createLocation").val()==this.locateMap.INMEASURE?"billID":"fxID"; if(selectedItem[updateField] == recode.ID) return; selectedItem[updateField] = recode.ID; if($("#createLocation").val()==this.locateMap.INMEASURE)selectedItem.billsLocation = recode.code; this.refreshSheetData(); }, applyTemplate:function () {//应用清单模板 let selected = projectObj.project.mainTree.selected; let template = projectObj.project.ration_template.getTemplateByRationID(selected.data.ID); let createLocation = $("#createLocation").val(); let rations = {update:[],create:[],delete:[]},bills={update:[],create:[]}; if(this.datas.length <= 0) return; for(let d of this.datas){ let ration = _.find(projectObj.project.Ration.datas,{'referenceRationID':selected.data.ID,'code':d.code}); if(ration||(gljUtil.isDef(d.quantity)&& parseFloat(d.quantity)>0)||(d.coe && d.coe!="0")){ if(this.positionChecking(createLocation,d) == false){//清单位置检查 alert(`请选择${d.code}生成的清单位置`); return; } this.getNodeUpdateData(d,selected.data.ID,createLocation,rations,bills); } } let ration_template={type:ModuleNames.ration_template,data:{ID:template.ID, createLocation:createLocation, templateList:this.datas}}; let data = { ration_template:ration_template, rations:rations, bills:bills }; console.log(data); $.bootstrapLoading.start(); CommonAjax.post('/ration/applyTemplate',data,function (result) { let parentsNodes = []; //先删除旧的定额 if(data.rations.delete.length > 0){ for(let d of data.rations.delete){ let dRaNode = projectObj.project.mainTree.getNodeByID(d.ID); if(dRaNode){ parentsNodes.push(dRaNode.parent); projectObj.project.Ration.deleteSubListOfRation({ID:d.ID}); _.remove(projectObj.project.Ration.datas,{'ID':d.ID}); projectObj.mainController.m_delete([dRaNode],dRaNode.serialNo(),false)//这里删除关联子目生成的定额因为是离散的树节点,所以要这样分开处理 } } } let refreshNodes = projectObj.project.updateNodesCache(result.updateDatas);//更新要update的前端缓存,并返回要刷新的树节点 let nodeDatas = {ration:{add:[]}, bills:{add:[]}}; if(result.rationResult){ for(let rr of result.rationResult){ nodeDatas.ration.add.push(rr.ration);//定额datas数据的push在addNodes里面做 projectObj.project.Ration.addSubListOfRation(rr);//添加定额子项缓存 } } //对于新插入的清单: if(result.billsResult.length > 0){ nodeDatas.bills.add = result.billsResult; } let calRations = ProjectController.addNewNodes(nodeDatas); if(refreshNodes.length > 0){ for(let r of refreshNodes){ if(r.sourceType == ModuleNames.ration){ calRations.push(r); if(r.data.quantityEXP =="MBGCL" ) projectObj.project.quantity_detail.cleanQuantityDetail(r,true); } } projectObj.mainController.refreshTreeNode(refreshNodes, false); } projectObj.project.projectGLJ.loadData(function () { $.bootstrapLoading.end(); cbTools.refreshFormulaNodes(); //更新计算程序模板,并进行重新计算 if(parentsNodes.length > 0) calRations = calRations.concat(parentsNodes);//计算被删除的子目关联定额的父节点 projectObj.project.calcProgram.calcNodesAndSave(calRations,function () { installationFeeObj.calcInstallationFee(); OVER_HEIGHT.reCalcOverHeightFee(); }); mbzm_obj.showApplySuccess(); }); }) }, showApplySuccess:function () { $(".applySuccess").show(); setTimeout(function () { $(".applySuccess").hide(); },1500) }, positionChecking(type,data){//这个要之后再测试一下 let validate = true; if(type == mbzm_obj.locateMap.INMEASURE){ if(!_.isEmpty(data.billID)){ let node = projectObj.project.mainTree.getNodeByID(data.billID); if(!node) validate = false;//ID有值,但是找不到,说明清单已经被删除 }else if(_.isEmpty(data.billsLocation)){ validate = false } }else if(type == mbzm_obj.locateMap.INFBFX){ if(_.isEmpty(data.fxID)) { validate = false; }else { let node = projectObj.project.mainTree.getNodeByID(data.fxID); if(!node) validate = false;//ID有值,但是找不到,说明分项已经被删除 } } return validate }, getNodeUpdateData:function(data,referenceRationID,type,rations,bills){ let quantity = this.getQuantity(data);//取实时或手输工程量 quantity = this.transferToRationQuantity(data.unit,quantity);//工程量要经过转换 let mainRation = projectObj.project.mainTree.getNodeByID(referenceRationID); let billsID=""; //先检查要更新的定额是否已经存在 let ration = this.getExistRation(data,referenceRationID,type,rations); if(ration) {//如果存在,则比较清耗量、工程量表达式是否一致 let tem = this.getRationData(ration,data,quantity);//取更新信息 if(tem){//如果不一致,则需要更新 rations.update.push(tem); } //在定额存在的情况下,不用往下执行了 return; } //定额不存在的情况下 if(type == mbzm_obj.locateMap.AFTERRATION) {//如果是生成在主定额后面的位置 this.createNewRationAfterMain(data,mainRation,quantity,rations); }else if(type == mbzm_obj.locateMap.INMEASURE){//生成在措施项目下 this.createNewRationInMeasure(data,mainRation,quantity,rations,bills); }else { this.createNewRationInFBFX(data,mainRation,quantity,rations,bills); } }, getRationData:function (ration,data,quantity) { let tem = {}; if (ration.quantity + "" != quantity) tem.quantity = quantity; if (gljUtil.isDef(data.coe) && data.coe != "0"&&ration.quantityEXP != "MBGCL") { tem.isFromDetail = 0; tem.quantityEXP = "MBGCL"; } if(!_.isEmpty(tem)) { tem.projectID = ration.projectID; tem.ID = ration.ID; tem.contain = projectObj.project.Ration.getContain(projectObj.project.mainTree.findNode(ration.billsItemID),tem.quantity); return tem; } return null; }, createNewRationAfterMain:function (data,mainRation,quantity,rations) { //生成新的定额 let newID = uuid.v1(); let serialNo = mainRation.data.serialNo+1; //如果已经有正要生成的定额,则取这个序号再加1 if(rations.create.length > 0){ serialNo = rations.create[rations.create.length -1].newData.serialNo + 1 } let n_ration = this.createNewRationData(data,newID,mainRation.data.ID,mainRation.data.billsItemID,serialNo,quantity,mainRation.data.libID); rations.create.push(n_ration); //处理其它兄弟节点的序号 let br = projectObj.project.Ration.getBillsSortRation(); for(let i = mainRation.data.serialNo;i 0){//如果update列表中有数据,要更新那里的序列号 let u = _.find(rations.update,{'ID':br[i].ID}); if(u){ u.serialNo += 1; continue; } } rations.update.push({ID:br[i].ID,projectID:br[i].projectID,serialNo:br[i].serialNo+1}) } }, createNewRationInMeasure:function (data,mainRation,quantity,rations,bills) { let controller = projectObj.mainController; let billsID=""; if(!_.isEmpty(data.billID)&&projectObj.project.mainTree.getNodeByID(data.billID)){ billsID = data.billID; }else {//剩下的就是没找到的 let rootNode = projectObj.project.Bills.getMeasureNode(controller); let leaveNodes = projectObj.mainController.tree.getLeavesNodes(rootNode.source); for(let n of leaveNodes){ if (!(n.data.calcBase&&n.data.calcBase!="")&& n.data.code&&(n.data.code ==data.billsLocation||n.data.code.indexOf(data.billsLocation) != -1)){//没有使用基数计算的清单 billsID = n.data.ID; break; } } if(billsID == ""){//还是没有找到的情况下,先查找是不是已经生成过了 if(bills.create.length > 0){ let t_b = _.find(bills.create,{"billsLocation":data.billsLocation}); if(t_b) billsID = t_b.ID; } } if(billsID == ""){//也没有生成过的情况下,要自动生成清单 //2018-12-19 对于新生成的清单,根据新清单编码的前6位去查询有没有完全匹配的清单,有的话将这一节点做为新清单的父项清单 let subNodes=[]; //默认没有找到编码匹配的就挂在技术措施项目下 let parentNode = projectObj.project.Bills.getAutoParentNode("措施费用"); if(data.billsLocation.length >= 6){ projectObj.mainController.tree.getAllSubNode(rootNode,subNodes); let tem_code = data.billsLocation.substr(0,6); let n_parentNode = _.find(subNodes,function (n) { return n.data.code == tem_code; }); if(n_parentNode) parentNode = n_parentNode; } billsID = uuid.v1(); let newBill = { ID:billsID, projectID: parseInt(projectObj.project.ID()), ParentID:parentNode.data.ID, NextSiblingID:-1, code:projectObj.project.Bills.newFormatCode(data.billsLocation), type:billType.BILL, billsLibId:projectObj.project.projectInfo.engineeringInfo.bill_lib[0].id,//projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib billsLocation : data.billsLocation//这个是用来在后端查找清单信息 }; let existB = projectObj.project.Bills.sameStdCodeBillsData(data.billsLocation);//对于多单位的清单 if (existB) { newBill.unit = existB.unit; } //将这个节点的上一节点的NextSiblingID设置为这个新清单 //先看有没有刚生成的清单,有的话直接修改最后一个清单的NextSiblingID即可 let lastIndex = this.getLastIndex(bills.create,"ParentID",parentNode.data.ID); if(bills.create.length > 0 && lastIndex!=-1){ bills.create[lastIndex].NextSiblingID = newBill.ID; }else if(parentNode.children.length > 0){//如果新生的没有找到的话,查看父节点下是否有子节点 let pre = parentNode.children[parentNode.children.length-1]; bills.update.push({ projectID:newBill.projectID,ID:pre.data.ID, NextSiblingID:newBill.ID}); } bills.create.push(newBill); } } //生成定额 let newID = uuid.v1(); let serialNo = 1; serialNo = this.checkAndGetSerialNo(serialNo,billsID,rations); //先查看刚生成的定额中有没有相同父清单,有的话取最后的一个序列号加1 let n_ration = this.createNewRationData(data,newID,mainRation.data.ID,billsID,serialNo,quantity,mainRation.data.libID); rations.create.push(n_ration); }, createNewRationInFBFX:function (data,mainRation,quantity,rations,bills) { let billsID = ""; let parentNode = projectObj.project.mainTree.getNodeByID(data.fxID); //分部分项这里,如果没选择位置,或者选择后又删除了,是无法到这一步的,所以不用像生成在清单那里做很多检查 if(!_.isEmpty(data.fxID)&&parentNode){ billsID = data.fxID; } if(billsID !=""){ //生成定额 let newID = uuid.v1(); let serialNo = 1; serialNo = this.checkAndGetSerialNo(serialNo,billsID,rations); let n_ration = this.createNewRationData(data,newID,mainRation.data.ID,billsID,serialNo,quantity,mainRation.data.libID,true); rations.create.push(n_ration); } }, getLastIndex:function (arrays,key,value) { let index = -1; for (let i = 0;i 0){//如果能找到则说明已经存在的清单 serialNo = parentBillsNode.children[parentBillsNode.children.length - 1].data.serialNo + 1 } } return serialNo }, getLastBrotherNewRation:function(billsItemID,rations){ let newData = null; for(let tem of rations){ if(tem.newData.billsItemID == billsItemID) newData = tem.newData; } return newData; }, createNewRationData:function (data,newID,referenceRationID,billsID,serialNo,quantity,libID,isFBFX) { let newData = projectObj.project.Ration.getTempRationData(newID,billsID,serialNo,rationType.ration); newData.referenceRationID = referenceRationID; newData.quantity = quantity; newData.quantityEXP = gljUtil.isDef(data.coe) && data.coe != "0"?"MBGCL":quantity+""; //这里还要生成根据清单生成含量,父清单如果是刚自动生成的,其工程量为0,含量也为0 newData.contain = projectObj.project.Ration.getContain(projectObj.project.mainTree.findNode(billsID),quantity); let temRation = this.getDefaultRationCreateData(newData,data.code,libID,isFBFX); return temRation; }, getDefaultRationCreateData:function(newData,code,libID,isFBFX){ let itemQuery = {userID: userID, rationRepId: libID, code: code}; let needInstall = false; if(projectObj.project.isInstall()) {//如果是安装工程,要看需不需要生成安装增加费 needInstall = isFBFX;//在分部分项插入的定额才需要定额安装增加费 } return{itemQuery:itemQuery,newData:newData,defaultLibID: rationLibObj.getDefaultStdRationLibID(),calQuantity:false,brUpdate:[],needInstall:needInstall} }, /* getQuantity:function (data) {//取最新的消耗量,需经过转换 if(data.unit){ let times = parseInt(data.unit); if(!isNaN(times)){ return scMathUtil.roundForObj(parseFloat(data.quantity)/times,getDecimal("ration.quantity"))+"" } } return data.quantity },*/ transferToRationQuantity:function (unit,quantity) { if(unit){ let times = parseInt(unit); if(!isNaN(times)){ return scMathUtil.roundForObj(parseFloat(quantity)/times,getDecimal("ration.quantity"))+"" } } return quantity; }, getExistRation:function (data,referenceRationID,type,updateRations) { let temRation = null; //先检查要更新的定额是否已经存在 let rations =_.filter(projectObj.project.Ration.datas,{'referenceRationID':referenceRationID,'code':data.code}); for(let r of rations){ if(type == mbzm_obj.locateMap.AFTERRATION){//如果是生成在主定额后面的位置 let mainRationNode = projectObj.project.mainTree.getNodeByID(referenceRationID); if(r.billsItemID == mainRationNode.data.billsItemID){//如果清单ID相同, 说明是兄弟节点,位置相同 temRation = r; break; } } let billsNode = projectObj.project.mainTree.getNodeByID(r.billsItemID); if(billsNode){//将父清单与要生成的清单比较,看是否一致 if(type == mbzm_obj.locateMap.INMEASURE && billsNode.data.type ==billType.BILL){ if(!_.isEmpty(data.billID)){ //说明生成位置已经有定额了,只需更新消耗量就好 if(data.billID == r.billsItemID){ temRation = r; break; } }else if(!_.isEmpty(data.billsLocation)){//按清单编号到找对应的位置 if(billsNode.data.code && billsNode.data.code.indexOf(data.billsLocation)!=-1) { temRation = r; break; } } }else if(type == mbzm_obj.locateMap.INFBFX && (billsNode.data.type ==billType.FX||billsNode.data.type ==billType.BX)){ if(!_.isEmpty(data.fxID) && data.fxID == r.billsItemID){//分项、补项下有对应的定额 temRation = r; break; } } } //如果没有执行到break,则说明这条定额是要被删除的 updateRations.delete.push({projectID:r.projectID,ID:r.ID}); } return temRation; }, hasReferenceRation:function (node) { if(node.sourceType == ModuleNames.ration){ let template = projectObj.project.ration_template.getTemplateByRationID(node.data.ID); if(template){ let ration = _.find(projectObj.project.Ration.datas,{'referenceRationID':node.data.ID}); if(ration) return true; } } return false; }, deleteReferenceRation:function (mainNodes,updateNodes) { let refNode = []; for(let m of mainNodes){ if(this.hasReferenceRation(m)){ let rations = _.filter(projectObj.project.Ration.datas,{'referenceRationID':m.data.ID}); for(let r of rations){ let temNode = projectObj.project.mainTree.getNodeByID(r.ID); if(temNode && updateNodes.indexOf(temNode) == -1){//能找到该节点,并且节点不在已经删除的列表中 refNode.push(temNode); updateNodes.push(temNode); projectObj.mainController.tree.getAllSubNode(temNode,updateNodes)//添加显示到造价书页面的主材、设备节点 } } } } return refNode; }, updateReferenceRationNodeQuantity:function (node) { let rationNodes = [],codeMap={}; let template = projectObj.project.ration_template.getTemplateByRationID(node.data.ID); if(template) { for(let t of template.templateList){ if(t.coe && t.coe!="0"){ codeMap[t.code] = t; } } let times = parseInt(node.data.unit); times = isNaN(times)?1:times;//工程量要乘以定额单位的倍数 let referenceRations = this.findReferenceRation(node.data.ID); for(let r of referenceRations ){ let t_tem = codeMap[r.code]; if(t_tem){ let rationQuantity = node.data.quantity?scMathUtil.roundForObj(node.data.quantity, getDecimal('ration.quantity')):0; let t_quantity = scMathUtil.roundForObj(rationQuantity * parseFloat(t_tem.coe)*times, getDecimal('ration.quantity')); //这个也要同步更新 let rnode = projectObj.project.mainTree.findNode(r.ID); if(rnode && r.quantityEXP == "MBGCL"){//表达式是模板工程量的才要同步更新 let t_times = parseInt(rnode.data.unit); t_times = isNaN(t_times)?1:t_times;//工程量要乘以定额单位的倍数 rnode.data.quantity = scMathUtil.roundForObj(t_quantity/t_times,getDecimal('ration.quantity')); rnode.data.contain = projectObj.project.Ration.getContain(rnode.parent,rnode.data.quantity); rnode.change = true; rationNodes.push(rnode) } } } } return rationNodes; }, findReferenceRation:function(rationID){ return _.filter(projectObj.project.Ration.datas,{'referenceRationID':rationID}) } }; $('#createLocation').change(function(){ let me = mbzm_obj; let pcol = _.findIndex(me.setting.header,{dataCode:"position"}); me.setting.header[pcol].visible = $(this).val() == mbzm_obj.locateMap.AFTERRATION?false:true; me.refreshSheetData(); }); $('#next_mbzm').click(function () { if (projectReadOnly) { return; } let mainSheet = projectObj.mainSpread.getActiveSheet(); let selection = mainSheet.getSelections()[0]; let node = projectObj.project.mainTree.selected; let index = node.serialNo(); let next = null; for(let i = index+1;i< projectObj.project.mainTree.items.length;i++){ let temNode = projectObj.project.mainTree.items[i]; if(temNode && temNode.sourceType == ModuleNames.ration){ let template = projectObj.project.ration_template.getTemplateByRationID(temNode.data.ID); if(template) { next = temNode; break; } } } if(next){ let row = next.serialNo(); let col = selection.col?selection.col:0; mainSheet.setSelection(row, col, selection.rowCount, selection.colCount); projectObj.mainController.setTreeSelected(next); mainSheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center); } }); $('#apply_mbzm').click(function () { if(projectReadOnly) return; mbzm_obj.applyTemplate(); });