|
@@ -200,12 +200,12 @@ module.exports = {
|
|
|
}
|
|
|
|
|
|
},
|
|
|
-
|
|
|
+ //导入清单
|
|
|
upload: async function(req, res){
|
|
|
let responseData = {
|
|
|
err: 0,
|
|
|
msg: '',
|
|
|
- data: null
|
|
|
+ data: []
|
|
|
};
|
|
|
const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
|
|
|
const uploadOption = {
|
|
@@ -230,79 +230,50 @@ module.exports = {
|
|
|
}
|
|
|
//导入表类型(09表lj、广联达gld)
|
|
|
const fileType = fields.fileType !== undefined && fields.fileType.length > 0 ? fields.fileType[0] : uploadType.lj;
|
|
|
- //广联达表始终插入到分部分项,将文件名重命名为分部分项触发导入到分部分项部分
|
|
|
- if(fileType === uploadType.gld){
|
|
|
- file.originalFilename = '广联达分部分项工程';
|
|
|
- }
|
|
|
// 重命名文件名
|
|
|
uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
|
|
|
fs.renameSync(file.path, uploadFullName);
|
|
|
|
|
|
- const sheet = excel.parse(uploadFullName);
|
|
|
- if (sheet[0] === undefined || sheet[0].data === undefined) {
|
|
|
+ const sheets = excel.parse(uploadFullName);
|
|
|
+ if (sheets[0] === undefined || sheets[0].data === undefined) {
|
|
|
throw 'excel没有对应数据';
|
|
|
}
|
|
|
- //获取表的列设置确定导入的格式是否合法(09、广联达)
|
|
|
- //console.log(sheet[0].data);
|
|
|
- let colMapping = getColMapping(sheet[0].data);
|
|
|
- console.log(fileType);
|
|
|
- console.log(`colMapping`);
|
|
|
- console.log(colMapping);
|
|
|
- console.log(`sheet[0].data`);
|
|
|
- console.log(sheet[0].data);
|
|
|
- if(!isValidSheet(colMapping, fileType)){
|
|
|
- throw `excel数据格式错误`;
|
|
|
- }
|
|
|
-
|
|
|
- //导入的数据是否含有固定行(分部分项、施工技术措施项目、施工组织措施项目,通过文件名判断)、确定导入位置
|
|
|
- let flag = getImportFlag(file.originalFilename);
|
|
|
- if(!flag){
|
|
|
- throw 'excel数据错误';
|
|
|
- }
|
|
|
- let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});
|
|
|
- let insertFixedBill = null;
|
|
|
-
|
|
|
- let vData = getValidImportData(colMapping, sheet[0].data, fixedBill);
|
|
|
- console.log(`vData`);
|
|
|
- console.log(vData);
|
|
|
- for(let rData of vData){
|
|
|
- let t = {};
|
|
|
- t.serialNo = rData[colMapping.serialNo];
|
|
|
- t.code = rData[colMapping.code];
|
|
|
- t.name = rData[colMapping.name];
|
|
|
- t.itemCharacterText = rData[colMapping.itemCharacterText];
|
|
|
- t.unit = rData[colMapping.unit];
|
|
|
- t.quantity = rData[colMapping.quantity];
|
|
|
- console.log(t);
|
|
|
- }
|
|
|
- // throw 'test';
|
|
|
- //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单
|
|
|
- if(!fixedBill){
|
|
|
- //分部分项工程(不可删除)应存在
|
|
|
- if(flag === fixedFlag.SUB_ENGINERRING){
|
|
|
- throw '项目不存在分部分项工程'
|
|
|
+ //出现错误的表表名,前端提示用
|
|
|
+ let invalidSheets = [];
|
|
|
+ let validSheets = {fbfx: [], jscsxm: [], zzcsxm: []};
|
|
|
+ //获得选择的导入的表及导入位置
|
|
|
+ const uploadWorkBook = fields.uploadWorkBook !== undefined && fields.uploadWorkBook.length > 0 ? JSON.parse(fields.uploadWorkBook[0]) : [];
|
|
|
+ //识别非法和合法表,sheetInfo存储前端勾选的表的位置索引以及选择的导入位置
|
|
|
+ for(let sheetInfo of uploadWorkBook){
|
|
|
+ let sheet = sheets[sheetInfo.sheetIdx];
|
|
|
+ if(sheet.data === undefined){
|
|
|
+ invalidSheets.push(sheet.name);
|
|
|
+ continue;
|
|
|
}
|
|
|
- //措施项目是否存在
|
|
|
- let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});
|
|
|
- if(!csxm){
|
|
|
- throw '项目不存在措施项目'
|
|
|
+ //获取表的列设置确定导入的格式是否合法(09、广联达)
|
|
|
+ let colMapping = getColMapping(sheet.data);
|
|
|
+ if(!isValidSheet(colMapping, fileType)){
|
|
|
+ invalidSheets.push(sheet.name);
|
|
|
+ continue;
|
|
|
}
|
|
|
- //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)
|
|
|
- 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;
|
|
|
- }
|
|
|
+ //合法的表
|
|
|
+ sheet.colMapping = colMapping;
|
|
|
+ //将合法的表按导入位置分类当做一个表来处理
|
|
|
+ if(validSheets[sheetInfo.position] !== undefined){
|
|
|
+ validSheets[sheetInfo.position].push(sheet)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //合并同类表并提取表的有效数据
|
|
|
+ let toImportSheets = [];
|
|
|
+ for(let uploadPosition in validSheets){
|
|
|
+ let validExcelData = [];
|
|
|
+ for(let uSheet of validSheets[uploadPosition]){
|
|
|
+ validExcelData = validExcelData.concat(getValidImportData(uSheet.colMapping, uSheet.data))
|
|
|
+ }
|
|
|
+ if(validSheets[uploadPosition].length > 0){
|
|
|
+ toImportSheets.push({position: uploadPosition, colMapping: validSheets[uploadPosition][0].colMapping, validExcelData: validExcelData});
|
|
|
}
|
|
|
- await billsData.model.create(insertFixedBill);
|
|
|
- fixedBill = insertFixedBill;
|
|
|
}
|
|
|
- console.log(`fixedBill--------------`);
|
|
|
- console.log(fixedBill);
|
|
|
//匹配的清单库
|
|
|
const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
|
|
|
let stdBills = [], stdJobs = [], stdCharacters = [];
|
|
@@ -311,22 +282,21 @@ module.exports = {
|
|
|
stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
|
|
|
stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
|
|
|
}
|
|
|
- //将excel数据转换成清单树结构数据
|
|
|
- let insertDatas = parseToBillData(getValidImportData(colMapping, sheet[0].data, fixedBill), colMapping, fixedBill, projectID, {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters});
|
|
|
- console.log(`insertDatas`);
|
|
|
- console.log(insertDatas);
|
|
|
- if(insertDatas.length === 0){
|
|
|
+ let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
|
|
|
+ //导入表
|
|
|
+ for(let importData of toImportSheets){
|
|
|
+ let updateFrontData = await importSheet(importData, req.session.sessionUser.id, projectID, stdData);
|
|
|
+ if(updateFrontData){
|
|
|
+ responseData.data.push(updateFrontData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(responseData.data.length === 0){
|
|
|
throw 'excel无有效数据';
|
|
|
}
|
|
|
- //删除相关数据
|
|
|
- let deleteDatas = await billsData.deepDeleteBill([fixedBill], req.session.sessionUser.id);
|
|
|
- //新增清单数据
|
|
|
- await billsData.importBills(insertDatas);
|
|
|
- //返回数据以更新前端
|
|
|
- if(insertFixedBill){
|
|
|
- insertDatas.push(insertFixedBill);
|
|
|
+ if(invalidSheets.length > 0){
|
|
|
+ let msg = invalidSheets.join('、');
|
|
|
+ responseData.msg = `${msg},导入失败`;
|
|
|
}
|
|
|
- responseData.data = {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
|
|
|
//删除暂存文件
|
|
|
fs.unlink(uploadFullName);
|
|
|
res.json(responseData);
|
|
@@ -343,13 +313,63 @@ module.exports = {
|
|
|
|
|
|
});
|
|
|
}
|
|
|
-
|
|
|
};
|
|
|
|
|
|
+//
|
|
|
+async function importSheet(importData, userID, projectID, stdData){
|
|
|
+ //导入位置的有固定行
|
|
|
+ let flag = getImportFlag(importData.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数据转换成清单树结构数据
|
|
|
+ let insertDatas = parseToBillData(importData.validExcelData, importData.colMapping, fixedBill, projectID, stdData);
|
|
|
+ /*if(insertDatas.length === 0){
|
|
|
+ throw 'excel无有效数据';
|
|
|
+ }*/
|
|
|
+ if(insertDatas.length === 0){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ //删除相关数据
|
|
|
+ let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
|
|
|
+ //新增清单数据
|
|
|
+ await billsData.importBills(insertDatas);
|
|
|
+ //返回数据以更新前端
|
|
|
+ if(insertFixedBill){
|
|
|
+ insertDatas.push(insertFixedBill);
|
|
|
+ }
|
|
|
+ return {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
|
|
|
+}
|
|
|
+
|
|
|
//是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列
|
|
|
function isValidSheet(colMapping, fileType){
|
|
|
- //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额
|
|
|
- let isValid = true;
|
|
|
function hasField(field, all){
|
|
|
for(let i of all){
|
|
|
if(field === i){
|
|
@@ -360,9 +380,11 @@ function isValidSheet(colMapping, fileType){
|
|
|
}
|
|
|
let needFields;
|
|
|
if(fileType === uploadType.lj){
|
|
|
+ //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额
|
|
|
needFields = ['serialNo', 'code', 'name', 'money'];
|
|
|
}
|
|
|
else {
|
|
|
+ //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细
|
|
|
needFields = ['serialNo', 'code', 'name', 'itemCharacterText', 'unit', 'quantity', 'quantityDetail', 'feeDetail'];
|
|
|
}
|
|
|
let hasFieldCount = 0;
|
|
@@ -372,7 +394,6 @@ function isValidSheet(colMapping, fileType){
|
|
|
}
|
|
|
}
|
|
|
return hasFieldCount === needFields.length;
|
|
|
- //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细
|
|
|
}
|
|
|
|
|
|
//提取excel表头列对应数据
|
|
@@ -390,9 +411,9 @@ function getColMapping(sheetData){
|
|
|
}
|
|
|
return [];
|
|
|
}
|
|
|
- let headRow = getHeadRow(sheetData);
|
|
|
//获取需要的表头列与列号对应关系
|
|
|
let colMapping = {};
|
|
|
+ let headRow = getHeadRow(sheetData);
|
|
|
for(let c = 0; c < headRow.length; c++){
|
|
|
if(headRow[c]){
|
|
|
headRow[c] = headRow[c].toString().replace(/\s/g, '');
|
|
@@ -438,7 +459,7 @@ function rowExistData(rowData){
|
|
|
return false;
|
|
|
}
|
|
|
//提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
|
|
|
-function getValidImportData(colMapping, sheetData, fixedBill){
|
|
|
+function getValidImportData(colMapping, sheetData){
|
|
|
let withingD = false;
|
|
|
let validData = [];
|
|
|
function isHead(rData){
|
|
@@ -459,9 +480,9 @@ function getValidImportData(colMapping, sheetData, fixedBill){
|
|
|
let rData = sheetData[r];
|
|
|
if(isHead(rData)){
|
|
|
withingD = true;
|
|
|
- if(fixedBill.name !== '施工组织措施项目'){
|
|
|
+ /* if(fixedBill.name !== '施工组织措施项目'){
|
|
|
r++;
|
|
|
- }
|
|
|
+ }*/
|
|
|
continue;
|
|
|
}
|
|
|
else if(isTail(rData)){
|
|
@@ -493,14 +514,9 @@ function getValidImportData(colMapping, sheetData, fixedBill){
|
|
|
return validData;
|
|
|
}
|
|
|
|
|
|
-function getImportFlag(sheetName){
|
|
|
- const fixedItem = {'分部分项': fixedFlag.SUB_ENGINERRING, '施工技术措施项目': fixedFlag.CONSTRUCTION_TECH, '施工组织措施项目': fixedFlag.CONSTRUCTION_ORGANIZATION};
|
|
|
- for(let flag in fixedItem){
|
|
|
- if(sheetName.includes(flag)){
|
|
|
- return fixedItem[flag];
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
+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 !== '';
|