/** * Created by jimiz on 2017/4/7. */ let mongoose = require('mongoose'); var billsData = require('../models/bills'); let ration_model = require('../models/ration'); let ProjectsData = require('../../pm/models/project_model').project; let logger = require("../../../logs/log_helper").logger; let quantity_detail = require("../facade/quantity_detail_facade"); let bill_facade = require("../facade/bill_facade"); let raiton_facade = require("../facade/ration_facade"); let stdBillsModel = mongoose.model('std_bills_lib_bills'); let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent'); let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter'); import fixedFlag from '../../common/const/bills_fixed'; let LZString = require('lz-string'); const uuidV1 = require('uuid/v1'); const billType ={ DXFY:1,//大项费用 FB:2,//分部 FX:3,//分项 BILL:4,//清单 BX:5//补项 }; //上传的09表、广联达表 const uploadType = {lj: 'lj', gld: 'gld'}; // 上传控件 const multiparty = require("multiparty"); const fs = require("fs"); // excel解析 const excel = require("node-xlsx"); //统一回调函数 var callback = function(req, res, err, message, data){ res.json({error: err, message: message, data: data}); }; module.exports = { getData: function(req, res){ var data = JSON.parse(req.body.data); billsData.getData(data.projectId, function(err, message, billsList){ if (err === 0) { callback(req, res, err, message, billsList); } else { callback(req, res, err, message, null); } }); }, getItemTemplate: function(req, res){ //var data = JSON.parse(req.body.data); billsData.getItemTemplate(function(err, message, billsItem){ if (billsItem) { callback(req, res, err, message, billsItem); } else { callback(req, res, err, message, null); } }); }, allocIDs: function(req, res){ billsData.allocIDs(function(err, message, data){ if (err) { callback(req, res, err, message, data); } else { callback(req, res, err, message, null); } }); }, //zhong 2017-9-1 updateCharacterContent: function (req, res) { let data = JSON.parse(req.body.data); let findSet = data.findSet, updateObj = data.updateObj, txtObj = data.txtObj; billsData.updateCharacterContent(findSet, updateObj, txtObj, function (err, message) { callback(req, res, err, message, null); }); }, updateBills: async function (req, res) { try{ let data = JSON.parse(req.body.data); await billsData.updateBills(data.updateDatas); callback(req, res, 0, 'success', null); } catch (err){ callback(req, res, 1, err, null); } }, updateBill: async function(request, response) { const data = JSON.parse(request.body.data); const findSet = data.findSet; const updateData = data.updateData; let settingData = {}; // 筛选出要保存在项目属性的设置 for (const index in updateData) { if (updateData[index].field === 'addRule') { settingData = updateData[index].value; delete updateData[index]; } } /* // 更新项目属性 const propertyUpdateData = { property: 'addRule', data: settingData };*/ //const projectResult = await ProjectsData.updateProjectProperty(findSet.projectID, propertyUpdateData); const result = await billsData.updateBill(findSet, updateData); const message = !result ? '修改失败' : '修改成功'; const err = !result ? 1 : 0; callback(request, response, err, message, null); }, singleDelete:async function(req, res){ let result={ error:0 } try { let data = req.body.data; data = JSON.parse(data); let tasks = generateSingleDeleteTasks(data); let resultData= await billsData.model.bulkWrite(tasks); //删除工程量明细 await quantity_detail.deleteByQuery({projectID: data.projectID, billID: data.ID}) ; result.data=resultData; }catch (err){ logger.err(err); result.error=1; result.message = err.message; } res.json(result); }, multiDelete:async function(req, res){ let result={ error:0 }; try { let data = req.body.data; data = JSON.parse(data); result.data=await doBillsOrRationsDelete(data); }catch (err){ logger.err(err); result.error=1; result.message = err.message; } res.json(result); }, getSectionInfo:async function(req, res){ let result={ error:0 } try { let data = req.body.data; data = JSON.parse(data); let sectionInfo= await bill_facade.getSectionInfo(data); result.data=sectionInfo; }catch (err){ logger.err(err); result.error=1; result.message = err.message; } res.json(result); }, reorganizeFBFX:async function(req,res){ let result={ error:0 } try { let data = req.body.data; data = JSON.parse(data); let reorganizeResult= await bill_facade.reorganizeFBFX(data); result.data=reorganizeResult; }catch (err){ logger.err(err); result.error=1; result.message = err.message; } res.json(result); }, pasteBlock:async function(req,res){ let result={ error:0 }; try { let data = req.body.data; data = JSON.parse(data); let pasteResult = await bill_facade.pasteBlock(data,req.session.sessionCompilation); result.data = pasteResult; }catch (err){ logger.err(err); result.error=1; result.message = err.message; } res.json(result); }, //下载导入清单示例 downloadExample: async function(request, response) { try { const filePath = './public/static/uploadExample.xlsx'; const stats = fs.statSync(filePath); // 下载相关header response.set({ 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=uploadExample.xlsx', 'Content-Length': stats.size }); fs.createReadStream(filePath).pipe(response); } catch (error) { response.end(error); } }, //导入清单 import: async function(req, res){ let responseData = { err: 0, msg: '', data: [] }; const form = new multiparty.Form(); form.parse(req, async function(err, fields, files) { try{ const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ? parseInt(fields.projectID[0]) : 0; if (projectID <= 0) { throw '参数错误'; } //导入清单数据 let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ? fields.compressData[0] : null; if(compressData === null){ throw 'excel没有对应数据' } let importData = JSON.parse(LZString.decompressFromUTF16(compressData)); //匹配的清单库 const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null; let stdBills = [], stdJobs = [], stdCharacters = []; if(billsLibId){ stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId ruleText'); stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false}); stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false}); } let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters}; //导入表 let importDateA = +new Date(); for(let position in importData){ if(importData[position].length > 0){ let updateFrontData = await importSheet(position, importData[position], req.session.sessionUser.id, projectID, stdData); if(updateFrontData){ responseData.data.push(updateFrontData); } } } let importDateB = +new Date(); console.log(`导入时间: ${importDateB - importDateA}=========================================================================`); res.json(responseData); } catch (error){ responseData.err = 1; console.log(error); responseData.msg = typeof error === 'object' ? '上传失败' : error; res.json(responseData); } }); } }; async function importSheet(position, excelBills, userID, projectID, stdData){ //导入位置的有固定行 let flag = getImportFlag(position); if(!flag){ throw 'excel数据错误'; } let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null}); let insertFixedBill = null; //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单 if(!fixedBill){ //分部分项工程(不可删除)应存在 if(flag === fixedFlag.SUB_ENGINERRING){ throw '项目不存在分部分项工程' } //措施项目是否存在 let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null}); if(!csxm){ throw '项目不存在措施项目' } //插入清单固定行(施工技术措施项目、施工组织措施项目可删除) insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1', ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL}; //更新前节点 let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null}); for(let preData of preDatas){ if(preData.NextSiblingID == -1){ await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}}); break; } } await billsData.model.create(insertFixedBill); fixedBill = insertFixedBill; } //将excel清单数据转换成完整清单数据(设置ParentID、匹配标准清单库) parseToCompleteBills(excelBills, fixedBill, stdData); //删除相关数据 let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID); //新增清单数据 await billsData.importBills(excelBills); //返回数据以更新前端 if(insertFixedBill){ excelBills.push(insertFixedBill); } return {fixedBill: fixedBill, insert: {bill: excelBills, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}}; } function getImportFlag(position){ const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION}; return fixedItem[position] ? fixedItem[position] : null; } function isDef(data){ return typeof data !== 'undefined' && data !== null && data !== ''; } //将前端解析生成的清单节点数据完善(ParentID、匹配标准清单) function parseToCompleteBills(excelBills, fixedBills, stdData){ //设置清单ParentID let rootID = fixedBills ? fixedBills.ID: -1; for(let bills of excelBills){ if(bills.nodeType === 'root'){ rootID = bills.ID; bills.ParentID = fixedBills.ID; } else { bills.ParentID = rootID; } delete bills.nodeType; matchStdBill(bills, stdData); } //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容 function matchStdBill(excelBill, stdData){ let isMatch = false; let regExp = /^\d{12}$/g; if(excelBill.code.length >8){ let nineCode = excelBill.code.substr(0, 9); for(let stdBill of stdData.stdBills){ //set programID if(nineCode == stdBill.code){ isMatch = true; excelBill.programID = stdBill.engineering ? stdBill.engineering : null; excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null; excelBill.ruleText = stdBill.ruleText ? stdBill.ruleText : ''; //set jobContent and itemCharacter let tempJob = [], tempCharacter = []; for(let billJob of stdBill.jobs){ for(let stdJob of stdData.stdJobs) { if (billJob.id == stdJob.id) { tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content}); } } } for(let billCharacter of stdBill.items){ for(let stdCharacter of stdData.stdCharacters){ if(billCharacter.id == stdCharacter.id){ let eigenvalue = []; for(let eValue of stdCharacter.itemValue){ eigenvalue.push({isSelected: false, value: eValue.value}); } tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue}); } } } excelBill.jobContent = tempJob; excelBill.itemCharacter = tempCharacter; } } } if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项 excelBill.type = billType.BX; } } } async function doBillsOrRationsDelete(data) { let billTask = []; let deleteBillIDs = []; let rationTask=[]; let deleteRationIDs=[]; let qd_query=null; let sub_query=null; if(data['bills']){ billTask = generateUpdateTasks(data['bills'],data.projectID,data.user_id); for(let b_key in data['bills']){ if(data['bills'][b_key]===true){ deleteBillIDs.push(b_key+''); } } if(deleteBillIDs.length>0){ qd_query={projectID: data.projectID, billID: {"$in": deleteBillIDs}}; } } if(data['ration']){ rationTask = generateUpdateTasks(data['ration'],data.projectID,data.user_id); for(let r_key in data['ration']){ if(data['ration'][r_key]===true){ deleteRationIDs.push(r_key+''); } } if(deleteRationIDs.length>0){ if(qd_query==null){//说明没删除清单 qd_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}}; }else { qd_query={ "$or":[ {projectID: data.projectID, billID: {"$in": deleteBillIDs}}, {projectID: data.projectID, rationID: {"$in": deleteRationIDs}} ] } } sub_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}}; } } //先删除工程量明细 if(qd_query!=null){ await quantity_detail.deleteByQuery(qd_query) ; } if(sub_query!=null){ await raiton_facade.deleteSubListByQuery(sub_query); } if(rationTask.length>0){ await ration_model.model.bulkWrite(rationTask);//删除定额 } if(billTask.length>0){ await billsData.model.bulkWrite(billTask);//删除清单 } return 'success'; } function generateSingleDeleteTasks(data) { let updateData = data.updateData; updateData[data.ID]=true; let tasks = generateUpdateTasks(updateData,data.projectID,data.user_id); return tasks; } function generateUpdateTasks(data,projectID,user_id) { let tasks=[]; let updateData = data; let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id}; for(let key in updateData){ let task={ updateOne:{ filter:{ ID:key, projectID:projectID } } }; if(updateData[key]===true){ //原先是假删除,现在改成真删除 task = { deleteOne:{ filter:{ ID:key, projectID:projectID } } } /* task.updateOne.update={ deleteInfo:deleteInfo };*/ }else { task.updateOne.update=updateData[key]; } tasks.push(task); } return tasks; }