|
@@ -15,7 +15,9 @@ const importXML = (() => {
|
|
|
getValue,
|
|
|
arrayValue,
|
|
|
getFee,
|
|
|
+ mergeFees,
|
|
|
getFlag,
|
|
|
+ getBool,
|
|
|
getItemsRecur,
|
|
|
} = util;
|
|
|
|
|
@@ -49,12 +51,13 @@ const importXML = (() => {
|
|
|
const rst = {
|
|
|
projectType: projectType.Project,
|
|
|
name: getValue(projectSrc, ['_Name']),
|
|
|
- engs: extractEngs(projectSrc),
|
|
|
+ engs: extractEngs(projectSrc, xmlObjMap),
|
|
|
property: {
|
|
|
compilationIllustrationProject: getValue(projectSrc, ['_Explains'])
|
|
|
},
|
|
|
basicInformation: extractBasicInfo(projectSrc)
|
|
|
- }
|
|
|
+ };
|
|
|
+ return rst;
|
|
|
}
|
|
|
// 从xml对象中提取基本信息相关
|
|
|
function extractBasicInfo(projectSrc) {
|
|
@@ -122,10 +125,10 @@ const importXML = (() => {
|
|
|
{ key: 'bidApproverCertNo', value: getValue(bidderInfo, ['_BidApproverCertNo']) }, // 投标单位审定人资格证书
|
|
|
{ key: 'bidApproveDate', value: getValue(bidderInfo, ['_BidApproveDate']) }, // 投标单位审定时间
|
|
|
];
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
// 从xml对象中提取单项工程数据
|
|
|
- function extractEngs(projectSrc) {
|
|
|
+ function extractEngs(projectSrc, xmlObjMap) {
|
|
|
const sectionWorks = arrayValue(projectSrc, ['ProjectInstallationWorkCost', 'SectionalWorks']);
|
|
|
return sectionWorks.map(src => {
|
|
|
countData.projectCount++;
|
|
@@ -133,23 +136,277 @@ const importXML = (() => {
|
|
|
projType: projectType.Engineering,
|
|
|
name: getValue(src, ['_Name']),
|
|
|
code: getValue(src, ['_Number']),
|
|
|
- tenders: extractTenders(src)
|
|
|
+ tenders: extractTenders(src, xmlObjMap)
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
// 从xml对象中提取单位工程数据
|
|
|
- function extractTenders(sectionWorkSrc) {
|
|
|
+ function extractTenders(sectionWorkSrc, xmlObjMap) {
|
|
|
const unitWorks = arrayValue(sectionWorkSrc, ['UnitWorks']);
|
|
|
- return unitWorks.map(src => {
|
|
|
+ return unitWorks.map(unitWorckSrc => {
|
|
|
countData.projectCount++;
|
|
|
countData.unitPriceFileCount++;
|
|
|
+ const fileName = getValue(unitWorckSrc, ['_FileName']);
|
|
|
+ const tenderXMLObj = xmlObjMap[fileName];
|
|
|
+ const src = getValue(tenderXMLObj, ['UnitWorks']); // 单位工程文件的数据
|
|
|
return {
|
|
|
projType: projectType.Tender,
|
|
|
name: getValue(src, ['_Name']),
|
|
|
code: getValue(src, ['_Number']),
|
|
|
+ engineering: getValue(src, ['_ProjectType']),
|
|
|
+ projectFeature: extractProjectFeature(src),
|
|
|
+ workSummary: extractWorkSummary(src),
|
|
|
+ fbfx: extractFBFX
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 提取工程特征数据
|
|
|
+ function extractProjectFeature(tenderSrc) {
|
|
|
+ // TODO 支持嵌套子项
|
|
|
+ const attrInfoItems = arrayValue(tenderSrc, ['AttrInfo', 'AttrInfoItem']);
|
|
|
+ return attrInfoItems.map(item => {
|
|
|
+ return { name: getValue(item, ['_Name']), value: getValue(item, ['_Value']) };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 提取大项费用
|
|
|
+ function extractWorkSummary(tenderSrc) {
|
|
|
+ const summaryList = arrayValue(tenderSrc, ['UnitWorksSummary']);
|
|
|
+ return summaryList.map(src => {
|
|
|
+ const item = {
|
|
|
+ code: getValue(src, ['_Number']),
|
|
|
+ name: getValue(src, ['_Name']),
|
|
|
+ quantity: getValue(src, ['_Quantity']),
|
|
|
+ calcBase: getValue(src, ['_QtyFormula']),
|
|
|
+ remark: getValue(src, ['_Remark']),
|
|
|
+ feeCode: getValue(src, ['_Code']) //费用字典
|
|
|
+ };
|
|
|
+ if (importFileKind === FileKind.tender) { // 投标
|
|
|
+ item.feeRate = getValue(src, ['_Rate']);
|
|
|
+ item.fees = [{
|
|
|
+ fieldName: 'common', totalFee: getValue(itemSrc, ['_Total']) || '0',
|
|
|
+ unitFee: getValue(src, ['_TechnicalAndEconomicIndex']) || '0'
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 从src子项的SummaryOfBasicCost中获取一部分费用
|
|
|
+ function getFeesFromBasicCost(src) {
|
|
|
+ const summaryCost = getValue(src, ['SummaryOfBasicCost']);
|
|
|
+ if (!summaryCost) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ // SummaryOfBasicCost中有用的价格只有:人工费、材料费、主材费、机械费、管理费、利润
|
|
|
+ return [
|
|
|
+ { fieldName: 'labour', totalFee: getValue(summaryCost, ['_Labor']) || '0' },
|
|
|
+ { fieldName: 'material', totalFee: getValue(summaryCost, ['_Material']) || '0' },
|
|
|
+ { fieldName: 'mainMaterial', totalFee: getValue(summaryCost, ['_MainMaterial']) || '0' },
|
|
|
+ { fieldName: 'machine', totalFee: getValue(summaryCost, ['_Machine']) || '0' },
|
|
|
+ { fieldName: 'manage', totalFee: getValue(summaryCost, ['_Overhead']) || '0' },
|
|
|
+ { fieldName: 'profit', totalFee: getValue(summaryCost, ['_Profit']) || '0' },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ // 提取分部分项
|
|
|
+ function extractFBFX(tenderSrc) {
|
|
|
+ const fbfxSrc = getValue(tenderSrc, ['DivisionalAndElementalWorks']);
|
|
|
+ const fields = [['DivisionalWorks'], ['WorkElement']];
|
|
|
+ const fees = getFeesFromBasicCost(fbfxSrc); // 分部分项的汇总价
|
|
|
+ const items = getItemsRecur(fbfxSrc, fields, (itemSrc, curField) => {
|
|
|
+ if (curField[0] === fields[0][0]) { // 分部
|
|
|
+ return extractDivisionalWorks(itemSrc);
|
|
|
+ } else {
|
|
|
+ return extractWorkElement(itemSrc, billType.FX);
|
|
|
}
|
|
|
});
|
|
|
+ return {
|
|
|
+ fees,
|
|
|
+ items
|
|
|
+ };
|
|
|
}
|
|
|
+ // 提取分部
|
|
|
+ function extractDivisionalWorks(divisionalSrc) {
|
|
|
+ // 分部不需要基数,因此不用把基数导入
|
|
|
+ const item = {
|
|
|
+ type: billType.FB,
|
|
|
+ code: getValue(divisionalSrc, ['_Number']),
|
|
|
+ name: getValue(divisionalSrc, ['_Name']),
|
|
|
+ unit: getValue(divisionalSrc, ['_Unit']),
|
|
|
+ quantity: getValue(divisionalSrc, ['_Quantity']),
|
|
|
+ feeCode: getValue(divisionalSrc, ['_Code']),
|
|
|
+ remark: getValue(divisionalSrc, ['_Remark']),
|
|
|
+ };
|
|
|
+ if (importFileKind === FileKind.tender) {
|
|
|
+ const summaryFees = getFeesFromBasicCost(divisionalSrc);
|
|
|
+ const fees = [{ fieldName: 'common', totalFee: getValue(divisionalSrc, ['_Total']), unitFee: getValue(divisionalSrc, ['_TechnicalAndEconomicIndex']) }];
|
|
|
+ item.fees = mergeFees(fees, summaryFees);
|
|
|
+ }
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ // 提取分项清单数据(包含定额、定额人材机)
|
|
|
+ function extractWorkElement(workElementSrc, type) {
|
|
|
+ // 分项不需要基数,因此不用把基数导入
|
|
|
+ const itemCharacterText = getItemCharacterText(getValue(workElementSrc, ['_Attr']));
|
|
|
+ const bills = {
|
|
|
+ type: type, // 清单类型
|
|
|
+ code: getValue(workElementSrc, ['_Number']),
|
|
|
+ name: getValue(workElementSrc, ['_Name']),
|
|
|
+ itemCharacterText,
|
|
|
+ itemCharacter: getItemCharacter(itemCharacterText),
|
|
|
+ jocContentText: getValue(workElementSrc, ['_WorkContent']),
|
|
|
+ jobContent: getJobContent(workElementSrc),
|
|
|
+ unit: getValue(workElementSrc, ['_Unit']),
|
|
|
+ quantity: getValue(workElementSrc, ['_Quantity']),
|
|
|
+ mainBills: getBool(getValue(workElementSrc, ['_Major'])),
|
|
|
+ feeCode: getValue(workElementSrc, ['_Code']),
|
|
|
+ remark: getValue(workElementSrc, ['_Remark']),
|
|
|
+ };
|
|
|
+ // 投标和控制价,需要导入最高限价
|
|
|
+ if ([FileKind.tender, FileKind.control].includes(importFileKind)) {
|
|
|
+ const maxPrice = getValue(workElementSrc, ['_PriceHigh']);
|
|
|
+ //不为0才输出
|
|
|
+ if (maxPrice && maxPrice !== '0') {
|
|
|
+ bills.outPutMaxPrice = true;
|
|
|
+ bills.maxPrice = maxPrice;
|
|
|
+ }
|
|
|
+ if (importFileKind === FileKind.tender) {
|
|
|
+ const summaryFees = getFeesFromBasicCost(workElementSrc);
|
|
|
+ const fees = [
|
|
|
+ { fieldName: 'common', unitFee: getValue(workElementSrc, ['_Price']), totalFee: getValue(workElementSrc, ['_Total']) },
|
|
|
+ { fieldName: 'equipment', unitFee: getValue(workElementSrc, ['_EquipmentPrice']) },
|
|
|
+ ];
|
|
|
+ bills.fees = mergeFees(fees, summaryFees);
|
|
|
+ // 输出定额数据
|
|
|
+ bills.rations = extractRations(workElementSrc);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 获取项目特征文本
|
|
|
+ function getItemCharacterText(attr) {
|
|
|
+ const matchStrs = ['
', ';'];
|
|
|
+ const matchStr = matchStrs.find(str => attr.includes(str));
|
|
|
+ return attr.replace(new RegExp(matchStr, 'g'), '\n');
|
|
|
+ }
|
|
|
+ // 获取清单项目特征窗口数据
|
|
|
+ function getItemCharacter(itemText) {
|
|
|
+ const itemsList = itemText.split('\n');
|
|
|
+ const reg = /\d+\.([^:]+)[::](.*)?/;
|
|
|
+ const itemCharacter = [];
|
|
|
+ let idx = 1;
|
|
|
+ itemsList.forEach(str => {
|
|
|
+ str = str.replace(/\s/g, '');
|
|
|
+ const result = reg.exec(str);
|
|
|
+ if (!result) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const name = result[1];
|
|
|
+ const value = result[2] || '';
|
|
|
+ const eigenvalue = value ? [{ value, isSelected: true }] : [];
|
|
|
+ itemCharacter.push({
|
|
|
+ character: name,
|
|
|
+ isChecked: true,
|
|
|
+ serialNo: idx++,
|
|
|
+ eigenvalue
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return itemCharacter;
|
|
|
+ }
|
|
|
+ // 获取清单工作内容窗口数据
|
|
|
+ function getJobContent(workElementSrc) {
|
|
|
+ return arrayValue(workElementSrc, ['WorkContent']).map((workContent, idx) => ({
|
|
|
+ content: getValue(workContent, ['_Name']),
|
|
|
+ serialNo: idx + 1,
|
|
|
+ isChecked: true
|
|
|
+ }));
|
|
|
+
|
|
|
+ }
|
|
|
+ // 提取定额
|
|
|
+ function extractRations(workElementSrc) {
|
|
|
+ // 正常情况下定额肯定是在WorkContent内的,但是也做定额不在WorkContent内的处理(外层定额)
|
|
|
+ const rations = [];
|
|
|
+ let serialNo = 1;
|
|
|
+ const workContents = arrayValue(workElementSrc, ['WorkContent']);
|
|
|
+ workContents.forEach(workContent => {
|
|
|
+ const innerRationsSrc = arrayValue(workContent, ['Norm']);
|
|
|
+ const jobContentText = getValue(workContent, ['_Name']);
|
|
|
+ const innerRations = innerRationsSrc.map(rationSrc => extractRation(rationSrc, jobContentText));
|
|
|
+ rations.push(...innerRations);
|
|
|
+ });
|
|
|
+ const outerRationsSrc = arrayValue(workElementSrc, ['Norm']);
|
|
|
+ const outerRations = outerRationsSrc.map(rationSrc => extractRation(rationSrc, ''));
|
|
|
+ rations.push(...outerRations);
|
|
|
+ return rations;
|
|
|
+ // 获取类型
|
|
|
+ function getType(rationSrc) {
|
|
|
+ const overHeightMap = {
|
|
|
+ '1': true,
|
|
|
+ '2': false
|
|
|
+ };
|
|
|
+ const isOverHeight = overHeightMap[getValue(rationSrc, ['EfficiencyKind'])];
|
|
|
+ if (isOverHeight) {
|
|
|
+ return rationType.overHeight;
|
|
|
+ }
|
|
|
+ const itemIncreaseMap = {
|
|
|
+ '1': true,
|
|
|
+ '2': false
|
|
|
+ };
|
|
|
+ const isItemIncrease = itemIncreaseMap[getValue(rationsSrc, ['IncFeeKind'])];
|
|
|
+ if (isItemIncrease) {
|
|
|
+ return rationType.itemIncrease;
|
|
|
+ }
|
|
|
+ return rationType.ration;
|
|
|
+ }
|
|
|
+ // 从定额的计算程序提取价格
|
|
|
+ function getFeesFromCalculationOfItem(rationSrc) {
|
|
|
+ const calculationOfItems = arrayValue(rationSrc, ['UnitPriceCalculationOfItem']);
|
|
|
+ const fees = [];
|
|
|
+ const codeFiedNameMap = {
|
|
|
+ 'DEZJF': 'direct',
|
|
|
+ 'RGF': 'labour',
|
|
|
+ 'CLF': 'material',
|
|
|
+ 'JXF': 'machine',
|
|
|
+ 'ZCF': 'mainMaterial',
|
|
|
+ 'SBF': 'equipment',
|
|
|
+ 'LR': 'profit',
|
|
|
+ 'DJ': 'common',
|
|
|
+
|
|
|
+ };
|
|
|
+ calculationOfItems.forEach(item => {
|
|
|
+ const totalFee = +getValue(item, ['_Total']);
|
|
|
+ const fieldName = codeFiedNameMap[getValue(item, ['_Code'])];
|
|
|
+ if (totalFee && fieldName) {
|
|
|
+ fees.push({ fieldName, totalFee });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return fees;
|
|
|
+ }
|
|
|
+ // 提取定额人材机
|
|
|
+ function extractRationGLJs(rationSrc) {
|
|
|
+ const rationGLJsSrc = arrayValue(rationSrc, ['LabourMaterialsEquipmentsMachinesElement']);
|
|
|
+ return rationGLJsSrc.map(src => ({
|
|
|
+ code: getValue(src, ['_Number']),
|
|
|
+ quantity: getValue(src, ['_Quantity'])
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ // TODO 目前无法确定定额的取费专业programID,暂时用专业类别Specialty
|
|
|
+ function extractRation(rationSrc, jobContentText) {
|
|
|
+ const ration = {
|
|
|
+ serialNo: serialNo++,
|
|
|
+ code: getValue(rationSrc, ['_Number']),
|
|
|
+ name: getValue(rationSrc, ['_Name']),
|
|
|
+ unit: getValue(rationSrc, ['_Unit']),
|
|
|
+ quantity: getValue(rationSrc, ['_Quantity']),
|
|
|
+ type: getType(rationSrc),
|
|
|
+ programID: getValue(rationSrc, ['_Specialty']),
|
|
|
+ libCode: getValue(rationSrc, ['_NormIdentity']),
|
|
|
+ jobContentText,
|
|
|
+ remark: getValue(rationSrc, ['_Remark'])
|
|
|
+ };
|
|
|
+ const fees = [{ fieldName: 'common', unitFee: getValue(rationSrc, ['_Price']), totalFee: getValue(rationSrc, ['_Total']) }]
|
|
|
+ const feesFromCalcItem = getFeesFromCalculationOfItem(rationSrc);
|
|
|
+ ration.fees = mergeFees(fees, feesFromCalcItem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 解压cos、zip文件
|
|
|
* @param {File} file - 上传的文件
|
|
@@ -186,7 +443,7 @@ const importXML = (() => {
|
|
|
xmlObjMap[fileName] = xmlObj;
|
|
|
}
|
|
|
//提取数据
|
|
|
- return loadData(xmlObjMap);
|
|
|
+ return extractProject(xmlObjMap);
|
|
|
};
|
|
|
|
|
|
// 接受上传的文件类型(不同的省份可以上传的文件不同)
|