|
@@ -15,6 +15,7 @@ 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,//大项费用
|
|
@@ -201,19 +202,13 @@ module.exports = {
|
|
|
|
|
|
},
|
|
|
//导入清单
|
|
|
- upload: async function(req, res){
|
|
|
+ import: async function(req, res){
|
|
|
let responseData = {
|
|
|
err: 0,
|
|
|
msg: '',
|
|
|
data: []
|
|
|
};
|
|
|
- const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
|
|
|
- const uploadOption = {
|
|
|
- uploadDir: './public'
|
|
|
- };
|
|
|
- const form = new multiparty.Form(uploadOption);
|
|
|
- let uploadFullName;
|
|
|
- let parseSheetDateA = +new Date();
|
|
|
+ const form = new multiparty.Form();
|
|
|
form.parse(req, async function(err, fields, files) {
|
|
|
try{
|
|
|
const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?
|
|
@@ -221,65 +216,13 @@ module.exports = {
|
|
|
if (projectID <= 0) {
|
|
|
throw '参数错误';
|
|
|
}
|
|
|
- const file = files.file !== undefined ? files.file[0] : null;
|
|
|
- if (err || file === null) {
|
|
|
- throw '上传失败';
|
|
|
- }
|
|
|
- // 判断类型
|
|
|
- if (file.headers['content-type'] === undefined || allowHeader.indexOf(file.headers['content-type']) < 0) {
|
|
|
- throw '不支持该类型';
|
|
|
- }
|
|
|
- //导入表类型(09表lj、广联达gld)
|
|
|
- const fileType = fields.fileType !== undefined && fields.fileType.length > 0 ? fields.fileType[0] : uploadType.lj;
|
|
|
- // 重命名文件名
|
|
|
- uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
|
|
|
- fs.renameSync(file.path, uploadFullName);
|
|
|
-
|
|
|
- const sheets = excel.parse(uploadFullName);
|
|
|
- if (sheets[0] === undefined || sheets[0].data === undefined) {
|
|
|
- throw 'excel没有对应数据';
|
|
|
- }
|
|
|
- //出现错误的表表名,前端提示用
|
|
|
- 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;
|
|
|
- }
|
|
|
- //获取表的列设置确定导入的格式是否合法(09、广联达)
|
|
|
- let colMapping = getColMapping(sheet.data);
|
|
|
- if(!isValidSheet(colMapping, fileType)){
|
|
|
- invalidSheets.push(sheet.name);
|
|
|
- continue;
|
|
|
- }
|
|
|
- //合法的表
|
|
|
- sheet.colMapping = colMapping;
|
|
|
- //将合法的表按导入位置分类当做一个表来处理
|
|
|
- if(validSheets[sheetInfo.position] !== undefined){
|
|
|
- validSheets[sheetInfo.position].push(sheet)
|
|
|
- }
|
|
|
+ //导入清单数据
|
|
|
+ let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ?
|
|
|
+ fields.compressData[0] : null;
|
|
|
+ if(compressData === null){
|
|
|
+ throw 'excel没有对应数据'
|
|
|
}
|
|
|
- let parseSheetB = +new Date();
|
|
|
- console.log(`解析表时间: ${parseSheetB - parseSheetDateA}===================================================================`);
|
|
|
- //合并同类表并提取表的有效数据
|
|
|
- let validSheetDataA = +new Date();
|
|
|
- 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});
|
|
|
- }
|
|
|
- }
|
|
|
- let validSheetDataB = +new Date();
|
|
|
- console.log(`获取表格有效数据时间: ${validSheetDataB - validSheetDataA}==========================================================`);
|
|
|
+ let importData = JSON.parse(LZString.decompressFromUTF16(compressData));
|
|
|
//匹配的清单库
|
|
|
let stdDateA = +new Date();
|
|
|
const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
|
|
@@ -290,33 +233,21 @@ module.exports = {
|
|
|
stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
|
|
|
}
|
|
|
let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
|
|
|
- let stdDateB = +new Date();
|
|
|
- console.log(`获取标准清单库数据时间: ${stdDateB - stdDateA}`);
|
|
|
//导入表
|
|
|
let importDateA = +new Date();
|
|
|
- for(let importData of toImportSheets){
|
|
|
- let updateFrontData = await importSheet(importData, req.session.sessionUser.id, projectID, stdData);
|
|
|
- if(updateFrontData){
|
|
|
- responseData.data.push(updateFrontData);
|
|
|
+ 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}=========================================================================`);
|
|
|
- if(responseData.data.length === 0){
|
|
|
- throw 'excel无有效数据';
|
|
|
- }
|
|
|
- if(invalidSheets.length > 0){
|
|
|
- let msg = invalidSheets.join('、');
|
|
|
- responseData.msg = `${msg},导入失败`;
|
|
|
- }
|
|
|
- //删除暂存文件
|
|
|
- fs.unlink(uploadFullName);
|
|
|
res.json(responseData);
|
|
|
}
|
|
|
catch (error){
|
|
|
- if(fs.existsSync(uploadFullName)){
|
|
|
- fs.unlink(uploadFullName);
|
|
|
- }
|
|
|
responseData.err = 1;
|
|
|
console.log(error);
|
|
|
responseData.msg = typeof error === 'object' ? '上传失败' : error;
|
|
@@ -327,10 +258,9 @@ module.exports = {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-//
|
|
|
-async function importSheet(importData, userID, projectID, stdData){
|
|
|
+async function importSheet(position, excelBills, userID, projectID, stdData){
|
|
|
//导入位置的有固定行
|
|
|
- let flag = getImportFlag(importData.position);
|
|
|
+ let flag = getImportFlag(position);
|
|
|
if(!flag){
|
|
|
throw 'excel数据错误';
|
|
|
}
|
|
@@ -361,169 +291,19 @@ async function importSheet(importData, userID, projectID, stdData){
|
|
|
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;
|
|
|
- }
|
|
|
+ //将excel清单数据转换成完整清单数据(设置ParentID、匹配标准清单库)
|
|
|
+ parseToCompleteBills(excelBills, fixedBill, stdData);
|
|
|
//删除相关数据
|
|
|
let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
|
|
|
//新增清单数据
|
|
|
- await billsData.importBills(insertDatas);
|
|
|
+ await billsData.importBills(excelBills);
|
|
|
//返回数据以更新前端
|
|
|
if(insertFixedBill){
|
|
|
- insertDatas.push(insertFixedBill);
|
|
|
- }
|
|
|
- return {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
|
|
|
-}
|
|
|
-
|
|
|
-//是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列
|
|
|
-function isValidSheet(colMapping, fileType){
|
|
|
- function hasField(field, all){
|
|
|
- for(let i of all){
|
|
|
- if(field === i){
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
- 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;
|
|
|
- for(let attr in colMapping){
|
|
|
- if(hasField(attr, needFields)){
|
|
|
- hasFieldCount++;
|
|
|
+ excelBills.push(insertFixedBill);
|
|
|
}
|
|
|
- }
|
|
|
- return hasFieldCount === needFields.length;
|
|
|
+ return {fixedBill: fixedBill, insert: {bill: excelBills, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
|
|
|
}
|
|
|
|
|
|
-//提取excel表头列对应数据
|
|
|
-function getColMapping(sheetData){
|
|
|
- //获取表头
|
|
|
- function getHeadRow(sheetData){
|
|
|
- for(let rData of sheetData) {
|
|
|
- //寻找含有序号的行,认作表头行
|
|
|
- for(let cData of rData){
|
|
|
- if (cData && cData.toString().replace(/\s/g, '') === '序号') {
|
|
|
- headRow = rData;
|
|
|
- return rData;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return [];
|
|
|
- }
|
|
|
- //获取需要的表头列与列号对应关系
|
|
|
- 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, '');
|
|
|
- //重复的,只取第一个
|
|
|
- if(headRow[c] === '序号' && colMapping.serialNo === undefined){
|
|
|
- colMapping.serialNo = c;
|
|
|
- }
|
|
|
- else if((headRow[c] === '编码' || headRow[c] === '项目编码') && colMapping.code === undefined){
|
|
|
- colMapping.code = c;
|
|
|
- }
|
|
|
- else if((headRow[c] === '名称' || headRow[c] === '项目名称') && colMapping.name === undefined){
|
|
|
- colMapping.name = c;
|
|
|
- }
|
|
|
- else if((headRow[c] === '特征' || headRow[c] === '项目特征') && colMapping.itemCharacterText === undefined){
|
|
|
- colMapping.itemCharacterText = c;
|
|
|
- }
|
|
|
- else if((headRow[c] === '单位' || headRow[c] === '计量单位') && colMapping.unit === undefined){
|
|
|
- colMapping.unit = c;
|
|
|
- }
|
|
|
- else if((headRow[c] === '工程量' || headRow[c] === '项目工程量') && colMapping.quantity === undefined){
|
|
|
- colMapping.quantity = c;
|
|
|
- }
|
|
|
- else if(headRow[c].includes('金额') && colMapping.money === undefined){
|
|
|
- colMapping.money = c;
|
|
|
- }
|
|
|
- else if(headRow[c] === '工程量明细' && colMapping.quantityDetail === undefined){
|
|
|
- colMapping.quantityDetail = c;
|
|
|
- }
|
|
|
- else if(headRow[c] === '费用明细' && colMapping.feeDetail === undefined){
|
|
|
- colMapping.feeDetail = c;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return colMapping;
|
|
|
-}
|
|
|
-function rowExistData(rowData){
|
|
|
- for(let cData of rowData){
|
|
|
- if(cData !== undefined && cData !== ''){
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-//提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
|
|
|
-function getValidImportData(colMapping, sheetData){
|
|
|
- let withingD = false;
|
|
|
- let validData = [];
|
|
|
- function isHead(rData){
|
|
|
- return rData[colMapping.serialNo] && rData[colMapping.serialNo].toString().replace(/\s/g, '') === '序号';
|
|
|
- }
|
|
|
- function isTail(rData){
|
|
|
- for(let cData of rData){
|
|
|
- if(cData){
|
|
|
- let trimCData = cData.toString().replace(/\s/g, '');
|
|
|
- if(trimCData === '本页小计' || trimCData === '本页小计'){
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
- for(let r = 0; r < sheetData.length; r++){
|
|
|
- let rData = sheetData[r];
|
|
|
- if(isHead(rData)){
|
|
|
- withingD = true;
|
|
|
- /* if(fixedBill.name !== '施工组织措施项目'){
|
|
|
- r++;
|
|
|
- }*/
|
|
|
- continue;
|
|
|
- }
|
|
|
- else if(isTail(rData)){
|
|
|
- withingD = false;
|
|
|
- }
|
|
|
- if(withingD && rowExistData(rData)){
|
|
|
- validData.push(rData);
|
|
|
- }
|
|
|
- /*if(rData[0]){
|
|
|
- //首列去空格
|
|
|
- rData[0] = rData[0].toString().replace(/\s/g, '');
|
|
|
- //表头
|
|
|
- if(rData[0] === '序号'){
|
|
|
- withingD = true;
|
|
|
- if(fixedBill.name !== '施工组织措施项目'){
|
|
|
- r++;
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
- //表尾
|
|
|
- else if(rData[0] === '本页小计' || rData[0] === '合计'){
|
|
|
- withingD = false;
|
|
|
- }
|
|
|
- }
|
|
|
- if(withingD && rowExistData(rData)){
|
|
|
- validData.push(rData);
|
|
|
- }*/
|
|
|
- }
|
|
|
- return validData;
|
|
|
-}
|
|
|
|
|
|
function getImportFlag(position){
|
|
|
const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION};
|
|
@@ -532,46 +312,22 @@ function getImportFlag(position){
|
|
|
function isDef(data){
|
|
|
return typeof data !== 'undefined' && data !== null && data !== '';
|
|
|
}
|
|
|
-//excel数据转换成清单数据
|
|
|
-function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
|
|
|
- let rst = [];
|
|
|
- let billIdx = {};
|
|
|
- let preRootID = -1,
|
|
|
- preLeafID = -1,
|
|
|
- preID = -1;
|
|
|
- //去除转义字符
|
|
|
- function removeESC(data){
|
|
|
- return isDef(data) ? data.toString().replace(/[\r,\n,\s,\t]/g, '') : data;
|
|
|
- }
|
|
|
- //父节点:1.无序号 2有编码
|
|
|
- function isRoot(rData){
|
|
|
- //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
|
|
|
- let serialNo = removeESC(rData[colMapping.serialNo]);
|
|
|
- let code = removeESC(rData[colMapping.code]);
|
|
|
- return !isDef(serialNo) && isDef(code);
|
|
|
- }
|
|
|
- //子节点:有序号
|
|
|
- function isLeaf(rData){
|
|
|
- let serialNo = removeESC(rData[colMapping.serialNo]);
|
|
|
- return isDef(serialNo);
|
|
|
- }
|
|
|
- //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
|
|
|
- function isExtend(preData, rData){
|
|
|
- let serialNo = removeESC(rData[colMapping.serialNo]);
|
|
|
- let code = removeESC(rData[colMapping.code]);
|
|
|
- let name = removeESC(rData[colMapping.name]);
|
|
|
- let itemCharacterText = removeESC(rData[colMapping.itemCharacterText]);
|
|
|
- return isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !isDef(serialNo) && !isDef(code) && (isDef(name) || isDef(itemCharacterText));
|
|
|
- }
|
|
|
- function getBillType(rData, flag){
|
|
|
- if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
|
|
|
- return billType.BILL;
|
|
|
+//将前端解析生成的清单节点数据完善(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 if(flag === fixedFlag.SUB_ENGINERRING){
|
|
|
- return isLeaf(rData) ? billType.FX : billType.FB;
|
|
|
+ else {
|
|
|
+ bills.ParentID = rootID;
|
|
|
}
|
|
|
- return null;
|
|
|
+ delete bills.nodeType;
|
|
|
+ matchStdBill(bills, stdData);
|
|
|
}
|
|
|
+
|
|
|
//excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容
|
|
|
function matchStdBill(excelBill, stdData){
|
|
|
let isMatch = false;
|
|
@@ -610,86 +366,9 @@ function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
|
|
|
}
|
|
|
}
|
|
|
if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项
|
|
|
- excelBill.type = billType.BX;
|
|
|
- }
|
|
|
- }
|
|
|
- for(let r = 0; r < validData.length; r++){
|
|
|
- /* //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
|
|
|
- let serialNo = validData[r][colMapping.serialNo];
|
|
|
- let code = validData[r][colMapping.code];
|
|
|
- if(isDef(serialNo)){
|
|
|
- serialNo = removeESC(serialNo);
|
|
|
- }
|
|
|
- if(isDef(code)){
|
|
|
- code = removeESC(code);
|
|
|
- }*/
|
|
|
- let preData = validData[r-1],
|
|
|
- rData = validData[r];
|
|
|
- if(fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] === '施工技术措施项目'
|
|
|
- || fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] === '施工组织措施项目'){
|
|
|
- continue;
|
|
|
+ excelBill.type = billType.BX;
|
|
|
}
|
|
|
- //过滤无效数据
|
|
|
- if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
|
|
|
- continue;
|
|
|
- }
|
|
|
- if(isExtend(preData, rData)){
|
|
|
- let preBill = billIdx[preID];
|
|
|
- if(preBill){
|
|
|
- //合并续数据
|
|
|
- preBill.code += rData[colMapping.code] ? rData[colMapping.code] : '';
|
|
|
- preBill.name += rData[colMapping.name] ? rData[colMapping.name] : '';
|
|
|
- preBill.itemCharacterText += rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '';
|
|
|
- preBill.unit += rData[colMapping.unit] ? rData[colMapping.unit] : '';
|
|
|
- preBill.quantity += rData[colMapping.quantity] ? rData[colMapping.quantity] : '';
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- let newID = uuidV1();
|
|
|
- let pID = -1;
|
|
|
- let preBill = null;
|
|
|
- if(isRoot(rData)){
|
|
|
- pID = fixedBill.ID;
|
|
|
- preBill = billIdx[preRootID];
|
|
|
- }
|
|
|
- else if(isLeaf(rData)){
|
|
|
- pID = preRootID !== -1 ? preRootID : fixedBill.ID;
|
|
|
- preBill = billIdx[preLeafID];
|
|
|
- }
|
|
|
- //set bill data
|
|
|
- billIdx[newID] = {
|
|
|
- ID: newID, ParentID: pID, NextSiblingID: -1,
|
|
|
- code: rData[colMapping.code] ? removeESC(rData[colMapping.code]) : '',
|
|
|
- name: rData[colMapping.name] ? removeESC(rData[colMapping.name]) : '',
|
|
|
- itemCharacterText: rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '',
|
|
|
- itemCharacter: [],
|
|
|
- jobContentText: '',
|
|
|
- jobContent: [],
|
|
|
- programID: null,
|
|
|
- unit: rData[colMapping.unit] ? rData[colMapping.unit] : '',
|
|
|
- quantity: rData[colMapping.quantity] ? rData[colMapping.quantity] : '',
|
|
|
- //安全文明
|
|
|
- flags: fixedBill.flags[0].flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] === '安全文明施工专项费用' || rData[colMapping.name] === '安全文明施工费') ?
|
|
|
- [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
|
|
|
- fees: [],
|
|
|
- projectID: projectID,
|
|
|
- type: getBillType(rData, fixedBill.flags[0].flag)};
|
|
|
- //match stdBill and reset programID、jobContent、itemCharacter
|
|
|
- matchStdBill(billIdx[newID], stdData);
|
|
|
- //update preBill NextSibling
|
|
|
- if(preBill){
|
|
|
- preBill.NextSiblingID = newID;
|
|
|
- }
|
|
|
- //set new preID
|
|
|
- preID = newID;
|
|
|
- preRootID = isRoot(rData) ? newID : preRootID;
|
|
|
- preLeafID = isLeaf(rData) ? newID : preLeafID;
|
|
|
- }
|
|
|
- }
|
|
|
- for(let i in billIdx){
|
|
|
- rst.push(billIdx[i]);
|
|
|
}
|
|
|
- return rst;
|
|
|
}
|
|
|
|
|
|
async function doBillsOrRationsDelete(data) {
|