'use strict'; const importXML = (() => { // 通用设置和工具 const config = importXMLBase.CONFIG; const util = importXMLBase.UTIL; const { fixedFlag, billType, rationType, projectType, TaxType, } = commonConstants; const { AdjustType } = config; const { getValue, arrayValue, getFee, mergeFees, getFlag, getBool, getItemsRecur, extractItemsRecur, } = util; //导入的文件类型,界面选的文件类型是生成项目的文件类型,这里的文件类型指的是,要导入文件的类型, //导入文件类型不同,导入数据不同 let importFileKind = ''; //文件类型 const FileKind = { '6': 1, // 投标 'tender': 1, '4': 2, // 招标 'bid': 2, '5': 3, // 控制价 'control': 3, }; const countData = { projectCount: 0, //项目数量 projectGLJCount: 0, //项目人材机数量 ratioCount: 0, //组成物数量 unitPriceCount: 0, //单价数量 unitPriceFileCount: 0, //单价文件数量 }; /* * 从导入的xml文件中提取有用的数据 * */ // 建设项目 function extractProject(xmlObjMap) { Object.keys(countData).forEach(key => countData[key] = 0); // 清缓存 countData.projectCount++; const projectXMLObj = xmlObjMap['Project.xml']; const projectSrc = getValue(projectXMLObj, ['ConstructionProject']); importFileKind = FileKind[getValue(projectSrc, ['_FileKind'])]; // 标记当前导入的文件类型 const rst = { projectType: projectType.Project, name: getValue(projectSrc, ['_Name']), engs: extractEngs(projectSrc, xmlObjMap), property: { compilationIllustrationProject: getValue(projectSrc, ['_Explains']) }, basicInformation: extractBasicInfo(projectSrc) }; countData.unitPriceCount = countData.projectGLJCount; if (importFileKind !== FileKind.tender) { countData = { projectCount: countData.projectCount, unitPriceFileCount: countData.unitPriceFileCount }; } return rst; } // 从xml对象中提取基本信息相关 function extractBasicInfo(projectSrc) { const projectInfo = getValue(projectSrc, ['ProjectInfo']); // 估概预算信息 const tendereeInfo = getValue(projectSrc, ['TendereeInfo']); // 招标信息 const bidderInfo = getValue(projectSrc, ['BidderInfo']); // 投标信息 return [ { key: 'projNum', value: getValue(projectSrc, ['_Number']) }, // 编码 { key: 'projectCategory', value: getValue(projectSrc, ['_ProjectCategory']) }, // 工程类别 { key: 'constructionType', value: getValue(projectSrc, ['_ConstructionType']) }, // 建设性质 { key: 'regionalCategories', value: getValue(projectSrc, ['_AreaKind']) }, // 地区类被 { key: 'projLocation', value: getValue(projectSrc, ['_ProjectSite']) }, // 工程地点 { key: 'constructingUnits', value: getValue(projectSrc, ['_BulidUnit']) }, // 建设单位 { key: 'constructingUnitsPerson', value: getValue(projectSrc, ['_BulidAuthorizer']) }, // 建设单位法定代表人或其授权人 { key: 'rangeOfCompilation', value: getValue(projectSrc, ['_RangeOfCompilation']) }, // 建设(编制)范围 { key: 'scale', value: getValue(projectSrc, ['_Scale']) }, // 建设规模 { key: 'unit', value: getValue(projectSrc, ['_Unit']) }, // 建设规模单位 { key: 'designUnits', value: getValue(projectInfo, ['_Designer']) }, // 设计单位 { key: 'constructionUnits', value: getValue(projectInfo, ['_Contractor']) }, // 承包单位 { key: 'establishUnit', value: getValue(projectInfo, ['_CompileCompany']) }, // 编制单位 { key: importFileKind === FileKind.tender ? 'bidCompileDate' : 'tenderCompileDate', value: getValue(projectInfo, ['_CompileDate']) }, // 编制时间 { key: 'authorizer', value: getValue(projectInfo, ['_Authorizer']) }, // 编制单位法定代表人或其授权人 { key: 'tendereeName', value: getValue(tendereeInfo, ['_TendereeName']) }, // 招标人 { key: 'tenderAuthorizer', value: getValue(tendereeInfo, ['_TenderAuthorizer']) }, // 招标单位法定代表人或其授权人 { key: 'tenderCompiler', value: getValue(tendereeInfo, ['_TenderCompiler']) }, // 招标单位编制人 { key: 'tenderCompilerCertNo', value: getValue(tendereeInfo, ['_TenderCompilerCertNo']) }, // 招标单位编制人资格证书编号 { key: 'tenderCompileDate', value: getValue(tendereeInfo, ['_TenderCompileDate']) }, // 招标单位编制时间 { key: 'tenderExaminer', value: getValue(tendereeInfo, ['_TenderExaminer']) }, // 招标单位审核人 { key: 'tenderExaminerCertNo', value: getValue(tendereeInfo, ['_TenderExaminerCertNo']) }, // 招标单位审核人资格证书编号 { key: 'tenderExamineDate', value: getValue(tendereeInfo, ['_TenderExamineDate']) }, // 招标单位审核时间 { key: 'tenderApprover', value: getValue(tendereeInfo, ['_TenderApprover']) }, // 招标单位审定人 { key: 'tenderApproverCertNo', value: getValue(tendereeInfo, ['_TenderApproverCertNo']) }, // 招标单位审定人资格证书编号 { key: 'proxy', value: getValue(tendereeInfo, ['_Proxy']) }, // 招标代理 { key: 'proxyCertNo', value: getValue(tendereeInfo, ['_ProxyCertNo']) }, // 招标代理资质证书编号 { key: 'proxyAuthorizer', value: getValue(tendereeInfo, ['_ProxyAuthorizer']) }, // 招标代理法定代表人或其授权人 { key: 'proxyCompiler', value: getValue(tendereeInfo, ['_ProxyCompiler']) }, // 招标代理编制人员 { key: 'proxyCompilerCertNo', value: getValue(tendereeInfo, ['_ProxyCompilerCertNo']) }, // 招标代理编制人员资格证书编号 { key: 'proxyCompileDate', value: getValue(tendereeInfo, ['_ProxyCompileDate']) }, // 招标代理编制时间 { key: 'proxyExaminer', value: getValue(tendereeInfo, ['_ProxyExaminer']) }, // 招标代理审核人 { key: 'proxyExaminerCertNo', value: getValue(tendereeInfo, ['_ProxyExaminerCertNo']) }, // 招标代理审核人资格证书编号 { key: 'proxyExamineDate', value: getValue(tendereeInfo, ['_ProxyExamineDate']) }, // 招标代理审核时间 { key: 'proxyApprover', value: getValue(tendereeInfo, ['_ProxyApprover']) }, // 招标代理审定人 { key: 'proxyApproverCertNo', value: getValue(tendereeInfo, ['_ProxyApproverCertNo']) }, // 招标代理审定人资格证书编号 { key: 'proxyApproveDate', value: getValue(tendereeInfo, ['_ProxyApproveDate']) }, // 招标代理审定时间 { key: 'consultant', value: getValue(tendereeInfo, ['_Consultant']) }, // 造价咨询 { key: 'consultantCertNo', value: getValue(tendereeInfo, ['_ConsultantCertNo']) }, // 造价咨询资质证书编号 { key: 'consultantCompiler', value: getValue(tendereeInfo, ['_ConsultantCompiler']) }, // 造价咨询编制人 { key: 'consultantCompilerCertNo', value: getValue(tendereeInfo, ['_ConsultantCompilerCertNo']) }, // 造价咨询编制人资格证书 { key: 'consultantCompileDate', value: getValue(tendereeInfo, ['_ConsultantCompileDate']) }, // 造价咨询编制时间 { key: 'consultantExaminer', value: getValue(tendereeInfo, ['_ConsultantExaminer']) }, // 造价咨询审核人 { key: 'consultantExaminerCertNo', value: getValue(tendereeInfo, ['_ConsultantExaminerCertNo']) }, // 造价咨询审核人资格证书编号 { key: 'consultantExamineDate', value: getValue(tendereeInfo, ['_ConsultantExamineDate']) }, // 造价咨询审核时间 { key: 'consultantApprover', value: getValue(tendereeInfo, ['_ConsultantApprover']) }, // 造价咨询审定人 { key: 'consultantApproverCertNo', value: getValue(tendereeInfo, ['_ConsultantApproverCertNo']) }, // 造价咨询审定人资格证书编号 { key: 'consultantApproveDate', value: getValue(tendereeInfo, ['_ConsultantApproveDate']) }, // 造价咨询审定时间 { key: 'bidName', value: getValue(bidderInfo, ['_BidName']) }, // 投标人 { key: 'bidAuthorizer', value: getValue(bidderInfo, ['_BidAuthorizer']) }, // 投标单位法定代表人或其授权人 { key: 'bidCompiler', value: getValue(bidderInfo, ['_BidCompiler']) }, // 投标单位编制人 { key: 'bidCompilerCertNo', value: getValue(bidderInfo, ['_BidCompilerCertNo']) }, // 投标单位编制人资格证书编号 { key: 'bidCompileDate', value: getValue(bidderInfo, ['_BidCompileDate']) }, // 投标单位编制时间 { key: 'bidExaminer', value: getValue(bidderInfo, ['_BidExaminer']) }, // 投标单位审核人 { key: 'bidExaminerCertNo', value: getValue(bidderInfo, ['_BidExaminerCertNo']) }, // 投标单位审核人资格证书编号 { key: 'bidExamineDate', value: getValue(bidderInfo, ['_BidExamineDate']) }, // 投标单位审核时间 { key: 'bidApprover', value: getValue(bidderInfo, ['_BidApprover']) }, // 投标单位审定人 { key: 'bidApproverCertNo', value: getValue(bidderInfo, ['_BidApproverCertNo']) }, // 投标单位审定人资格证书 { key: 'bidApproveDate', value: getValue(bidderInfo, ['_BidApproveDate']) }, // 投标单位审定时间 ]; } // 从xml对象中提取单项工程数据 function extractEngs(projectSrc, xmlObjMap) { const sectionWorks = arrayValue(projectSrc, ['ProjectInstallationWorkCost', 'SectionalWorks']); return sectionWorks.map(src => { countData.projectCount++; return { projType: projectType.Engineering, name: getValue(src, ['_Name']), code: getValue(src, ['_Number']), tenders: extractTenders(src, xmlObjMap) } }); } // 从xml对象中提取单位工程数据 function extractTenders(sectionWorkSrc, xmlObjMap) { const unitWorks = arrayValue(sectionWorkSrc, ['UnitWorks']); 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(src), csxm: extractCSXM(src), other: extractOther(src), tax: extractTax(src), ...extractGLJSummary(src), bidEvaluationSummary: extractBidEvaluationSummary(src) }; }); } // 提取工程特征数据 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 summarySrc = getValue(tenderSrc, ['UnitWorksSummary']); const fields = [['UnitWorksSummaryGroup'], ['UnitWorksSummaryItem']]; return extractItemsRecur(summarySrc, fields, (src, curField) => { const item = { code: getValue(src, ['_Number']), name: getValue(src, ['_Name']), quantity: getValue(src, ['_Quantity']), remark: getValue(src, ['_Remark']), feeCode: getValue(src, ['_Code']), //费用字典 fees: [{ fieldName: 'common', totalFee: getValue(src, ['_Total']) || '0', unitFee: getValue(src, ['_TechnicalAndEconomicIndex']) || '0' }] }; if (curField[0] === fields[1][0]) { item.calcBase = getValue(src, ['_QtyFormula']); item.feeRate = getValue(src, ['_Rate']); } if (importFileKind !== FileKind.tender) { delete item.feeRate delete item.fees; } return item; }); } // 从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, billType.FB); } else { return extractWorkElement(itemSrc, billType.FX); } }); return { fees, items }; } // 提取分部 function extractDivisionalWorks(divisionalSrc, type) { // 分部不需要基数,因此不用把基数导入 const item = { type, 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']), calcBase: getValue(workElementSrc, ['_QtyFormula']), feeRate: getValue(workElementSrc, ['_Rate']), mainBills: getBool(getValue(workElementSrc, ['_Major'])), feeCode: getValue(workElementSrc, ['_Code']), remark: getValue(workElementSrc, ['_Remark']), rations: extractRations(workElementSrc) }; // 投标和控制价,需要导入最高限价 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); } } return bills; // 获取项目特征文本 function getItemCharacterText(attr) { // 去掉除换行符以外的空白符 const newLine = '{newLine}'; attr = attr .replace(/[\r\n]/g, newLine) .replace(/\s/g, '') .replace(new RegExp(newLine, 'g'), '\n'); const matchStrs = [' ', ';']; const matchStr = matchStrs.find(str => attr.includes(str)); if (matchStr) { attr = attr.replace(new RegExp(matchStr, 'g'), '\n'); } return attr; } // 获取清单项目特征窗口数据 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) { if (importFileKind !== FileKind.tender) { return []; } // 正常情况下定额肯定是在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(rationSrc, ['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); ration.rationGLJs = extractRationGLJs(rationSrc); return ration; } } // 提取措施项目 function extractCSXM(tenderSrc) { const csxmSrc = getValue(tenderSrc, ['Preliminaries']); const fields = [['DivisionalWorks'], ['WorkElement']]; const fees = getFeesFromBasicCost(csxmSrc); // 措施项目的汇总价 const items = getItemsRecur(csxmSrc, fields, (itemSrc, curField) => { if (curField[0] === fields[0][0]) { return extractDivisionalWorks(itemSrc, billType.BILL); } else { return extractWorkElement(itemSrc, billType.BILL); } }); return { fees, items }; } // 提取其他项目 function extractOther(tenderSrc) { const sundry = getValue(tenderSrc, ['Sundry']); // SundryCosts 其他项目 ,对于我们软件是其他项目下完整数据,但是广联达的并不是,因此需要Sundry的其他节点来补充这份数据 const sundryCosts = getValue(sundry, ['SundryCosts']); // 其他项目汇总费用 const sundryFees = [{ fieldName: 'common', totalFee: getValue(sundryCosts, ['_Total']) }]; debugger; return { fees: importFileKind === FileKind.tender ? sundryFees : [], sundryCosts: extractData(sundry, 'SundryCosts', [['SundryCostsGroup'], ['SundryCostsItem']]), provisional: extractData(sundry, 'ProvisionalSums', [['ProvisionalSumsGroup'], ['ProvisionalSumsItem']]), specialty: extractData(sundry, 'SpecialtyProvisionalPrice', [['SpecialtyProvisionalPriceGroup'], ['SpecialtyProvisionalPriceItem']], { engineeringContent: ['_Content'] }, { engineeringContent: ['_Content'] }), dayWork: extractData(sundry, 'DayWorkRate', [['DayWorkRateGroup'], ['DayWorkRateItem']]), mainContractor: extractData(sundry, 'MainContractorAttendance', [['MainContractorAttendanceGroup'], ['MainContractorAttendanceItem']], { serviceContent: ['_Content'] }), claim: extractData(sundry, 'ClaimsCost', [['ClaimsCostGroup'], ['ClaimsCostItem']]), visa: extractData(sundry, 'SiteInstructionCost', [['SiteInstructionCostGroup'], ['SiteInstructionCostItem']]), }; // 提取标题和明细 function extractGroupOrItem(itemSrc, isGroup = true, extendAttrs = null) { const source = isGroup ? { name: getValue(itemSrc, ['_Name']), fees: importFileKind === FileKind.tender ? [{ fieldName: 'common', totalFee: getValue(itemSrc, ['_Total']) }] : [], feeCode: getValue(itemSrc, ['_Code']), remark: getValue(itemSrc, ['_Remark']) } : { name: getValue(itemSrc, ['_Name']), unit: getValue(itemSrc, ['_Unit']), quantity: getValue(itemSrc, ['_Quantity']), calcBase: getValue(itemSrc, ['_QtyFormula']), feeRate: getValue(itemSrc, ['_Rate']), fees: importFileKind === FileKind.tender ? [{ fieldName: 'common', unitFee: getValue(itemSrc, ['_Price']), totalFee: getValue(itemSrc, ['_Total']) }] : [], feeCode: getValue(itemSrc, ['_Code']), remark: getValue(itemSrc, ['_Remark']) }; return extendAttrs ? Object.assign(source, extendAttrs) : source; } // 提取数据 function extractData(sundry, srcName, fields, groupExtendMap, itemExtendMap) { const src = getValue(sundry, [srcName]); return extractItemsRecur(src, fields, (itemSrc, curField) => { const groupExtend = groupExtendMap ? Object.keys(groupExtendMap).reduce((acc, key) => { acc[key] = getValue(itemSrc, groupExtendMap[key]); return acc; }, {}) : null; const itemExtend = itemExtendMap ? Object.keys(itemExtendMap).reduce((acc, key) => { acc[key] = getValue(itemSrc, itemExtendMap[key]); return acc; }, {}) : null; return curField[0] === fields[0][0] ? extractGroupOrItem(itemSrc, true, groupExtend) : extractGroupOrItem(itemSrc, false, itemExtend); }); } // TODO 材料设备暂估价明细 } // 提取税金 function extractTax(tenderSrc) { const taxSrc = getValue(tenderSrc, ['Tax']); const itemsSrc = arrayValue(taxSrc, ['TaxItem']); return { ...extractTaxItem(taxSrc), items: itemsSrc.map(extractTaxItem) }; function extractTaxItem(src) { return { name: getValue(src, ['_Name']), calcBase: getValue(src, ['_QtyFormula']), feeRate: getValue(src, ['_Rate']), fees: importFileKind === FileKind.tender ? [{ fieldName: 'common', totalFee: getValue(src, ['_Total']) }] : [], feeCode: getValue(src, ['_Code']), remark: getValue(src, ['_Remark']) }; } } // 供料方式 const Provider = { '1': [commonConstants.supplyType.ZXCG], '2': [commonConstants.supplyType.BFJG], '3': [commonConstants.supplyType.WQJG] }; // 提取人材机汇总相关(人材机汇总表、承包材料表) function extractGLJSummary(tenderSrc) { const initData = { gljSummary: [], differentiaSummary: [], exponentialSummary: [] }; if (importFileKind !== FileKind.tender) { return initData; } const taxType = getValue(tenderSrc, ['_TaxModel']); // 计税方式 const gljListSrc = arrayValue(tenderSrc, ['LabourMaterialsEquipmentsMachinesSummary']); return gljListSrc.reduce((acc, gljSrc) => { acc.gljSummary.push(extractGLJ(gljSrc)); acc.differentiaSummary.push(extractDifferentiaGLJ(gljSrc)); acc.exponentialSummary.push(extractExponentialGLJ(gljSrc)); return acc; }, initData); // 获取原始编码 function getOriginalCode(code) { //编码后面有-\d+的形式,去掉-\d+取前面的字符串作为原始代码 return code.replace(/(.*)-\d+$/, '$1'); } // TODO (不靠谱) 获取人材机类型数据 // 导入的源文件没有细化区分人材机类型,这里只是暂时大概给个值。后续会在后端与标准人材机进行配对。也因此无法准确处理补充人材机 function getTypeData(gljSrc) { const concrete = getBool(getValue(gljSrc, ['_Concrete'])); if (concrete) { return { type: 205, shorName: '商砼' }; } const type = getValue(gljSrc, ['_Kind']); switch (type) { case '6': return { type: 202, shorName: '砼' }; case '7': return { type: 301, shorName: '机' }; case '15': return { type: 6, shortName: '管' }; default: return { type: 201, shortName: '材' }; } } // 根据计税方式获取价格,一般计税对应不含税,简易对应含税 function getPriceByTaxType(gljSrc, taxType) { return taxType === TaxType.NORMAL ? { base_price: getValue(gljSrc, ['_NoTaxOrgPrice']), market_price: getValue(gljSrc, ['_NoTaxPrice']) } : { base_price: getValue(gljSrc, ['_TaxOrgPrice']), market_price: getValue(gljSrc, ['_TaxPrice']) }; } // 提取组成物 function extractRatios(gljSrc) { const ratiosSrc = arrayValue(gljSrc, ['LabourMaterialsEquipmentsMachinesElement']); countData.ratioCount += ratiosSrc.length; return ratiosSrc.map(src => ({ code: getValue(src, ['_Number']), consumption: getValue(src, ['_Quantity']) })); } // 提取项目人材机 function extractGLJ(gljSrc) { countData.projectGLJCount++; const code = getValue(gljSrc, ['_Number']); return { code, original_code: getOriginalCode(code), name: getValue(gljSrc, ['_Name']), specs: getValue(gljSrc, ['_Specification']), unit: getValue(gljSrc, ['_Unit']), ...getTypeData(gljSrc), ...getPriceByTaxType(gljSrc, taxType), // 软件中项目人材机是没有价格的,只是为了后续处理单价文件 is_main_material: getBool(getValue(gljSrc, ['_MainMaterial'])), is_evaluate: getBool(getValue(gljSrc, ['_ProvisionalMaterial'])), supply: Provider[getValue(gljSrc, ['_Provider'])], delivery: getValue(gljSrc, ['_Delivery']), delivery_address: getValue(gljSrc, ['_Location']), originPlace: getValue(gljSrc, ['_ProducingArea']), vender: getValue(gljSrc, ['_Supplier']), qualityGrace: getValue(gljSrc, ['_Character']), remark: getValue(gljSrc, ['_Remark']), ratios: extractRatios(gljSrc) }; } // 提取造价信息差额调整法 function extractDifferentiaGLJ(gljSrc) { return { code: getValue(gljSrc, ['_Number']), name: getValue(gljSrc, ['_Name']), specs: getValue(gljSrc, ['_Specification']), unit: getValue(gljSrc, ['_Unit']), quantity: getValue(gljSrc, ['_Quantity']), riskCoe: getValue(gljSrc, ['_ProviderExp']), standardPrice: getValue(gljSrc, ['_ProviderBase']), market_price: getPriceByTaxType(gljSrc, taxType).market_price, remark: getValue(gljSrc, ['_Remark']), }; } // 提取价格指数调整法 function extractExponentialGLJ(gljSrc) { return { code: getValue(gljSrc, ['_Number']), name: getValue(gljSrc, ['_Name']), specs: getValue(gljSrc, ['_Specification']), varWeight: getValue(gljSrc, ['_Weight']), FO: getValue(gljSrc, ['_BasicPrice']), FI: getValue(gljSrc, ['_CurrentPrice']), remark: getValue(gljSrc, ['_Remark']) }; } } // 提取评标材料 function extractBidEvaluationSummary(tenderSrc) { if (importFileKind !== FileKind.tender) { return []; } const srcList = arrayValue(tenderSrc, ['BidEvaluationMainMaterial']); return srcList.map(src => ({ seq: getValue(gljSrc, ['_Code']), code: getValue(gljSrc, ['_Number']), name: getValue(gljSrc, ['_Name']), specs: getValue(gljSrc, ['_Specification']), unit: getValue(gljSrc, ['_Unit']), quantity: getValue(gljSrc, ['_Quantity']), market_price: getValue(gljSrc, ['_Price']), originPlace: getValue(gljSrc, ['_ProducingArea']), vender: getValue(gljSrc, ['_Supplier']), remark: getValue(gljSrc, ['_Remark']) })); } /* * 转换从xml提取的数据,转换成软件所需的数据结构 * */ async function transformData(extractedData) { const IDPlaceholder = await ajaxPost('/pm/import/getProjectPlaceholder', countData); extractedData.ID = IDPlaceholder.project++; // 最终上传到服务器的转换后的数据 const transformedData = { ID: extractedData.ID, ParentID: extractedData.ParentID, NextSiblingID: extractedData.NextSiblingID, preID: extractedData.preID, name: extractedData.name, basicInformation: extractedData.basicInformation, projType: extractedData.projType, property: extractedData.property, shareInfo: [], engs: [] }; // 所有的清单模板库ID const allTemplateLibIDs = []; extractedData.engs.forEach(eng => { eng.tenders.forEach(tender => { let templateLibID = tender.property.templateLibID; if (!allTemplateLibIDs.includes(templateLibID)) { allTemplateLibIDs.push(templateLibID); } }); }); // 模板映射:{[templateLibID]: data} const templateMapping = await ajaxPost('/template/bills/api/getNeedfulTemplate', { allTemplateLibIDs }); for (let i = 0; i < extractedData.engs.length; i++) { const curEng = extractedData.engs[i]; const preEng = transformedData.engs[i - 1]; curEng.ID = IDPlaceholder.project++; curEng.ParentID = extractedData.ID; curEng.NextSiblingID = -1; if (preEng) { preEng.NextSiblingID = curEng.ID; } const engData = { ID: curEng.ID, ParentID: curEng.ParentID, NextSiblingID: curEng.NextSiblingID, code: curEng.code, name: curEng.name, projType: curEng.projType, shareInfo: [], tenders: [] }; transformedData.engs.push(engData); for (let j = 0; j < curEng.tenders.length; j++) { const curTender = curEng.tenders[j]; const preTender = engData.tenders[j - 1]; curTender.ID = IDPlaceholder.project++; curTender.ParentID = curEng.ID; curTender.NextSiblingID = -1; curTender.property.unitPriceFile.id = IDPlaceholder.unitPriceFile++; if (preTender) { preTender.tender.NextSiblingID = curTender.ID; } // 项目清单模板(后台清单模板中提取含有固定类别的数据) const projectBills = _.cloneDeep(templateMapping[curTender.property.templateLibID]); debugger; // 重设模板树结构数据 BILLS_UTIL.resetTreeData(projectBills, uuid.v1); console.log(projectBills); const tenderData = transformTender(curTender, IDPlaceholder, projectBills); tenderData.tender.property.rootProjectID = transformedData.ID; engData.tenders.push(tenderData); } } return transformedData; } // 转换单位工程的数据(直接可插入数据库的数据),返回{tender: {}, bills: [], ration: [], rationGLJ: [], projectGLJ: [], unitPrice: [], mixRatio: []} function transformTender(tenderData, IDPlaceholder, projectBills) { const detailData = transformDetail(tenderData, IDPlaceholder, projectBills); // 提取需要插入的单位工程数据 const transformedTender = { ID: tenderData.ID, ParentID: tenderData.ParentID, NextSiblingID: tenderData.NextSiblingID, code: tenderData.code, name: tenderData.name, projType: tenderData.projType, property: tenderData.property, projectFeature: tenderData.projectFeature, engineering: tenderData.engineering, defaultRationLib: tenderData.defaultRationLib, rationLibIDs: tenderData.rationLibIDs, gljLibIDs: tenderData.gljLibIDs, shareInfo: [] }; transformedTender.property.gljAdjustType = AdjustType.info; detailData.tender = transformedTender; return detailData; } // 转换清单 function transformBills(tenderData, IDPlaceholder, projectBills) { } // 转换详细的项目数据,清单、定额、定额人材机、项目人材机、单价文件等 function transformDetail() { } /** * 解压cos、zip文件 * @param {File} file - 上传的文件 * @return {Object} 解压出来的xml文件名称与xml文件文本内容映射 */ async function unzipFile(file) { const jsZip = new JSZip(); const zip = await jsZip.loadAsync(file); const map = {}; for (const fileName in zip.files) { // 将二进制数据转换成字符串 map[fileName] = await jsZip.file(fileName).async('string'); } return map; } //从xml文件中提取数据 async function extractData(file, escape = false) { const fileMap = await unzipFile(file); const projectXML = fileMap['Project.xml']; if (!projectXML) { throw '无有效数据'; } const xmlObjMap = {}; for (const fileName in fileMap) { // x2js转换xml使用了DomParser接口,会将一些字符实体进行转义。若不想被自动转义,则需要调用escapeXMLEntity const xmlStr = escape ? util.escapeXMLEntity(fileMap[fileName]) : fileMap[fileName]; //将xml格式良好的字符串转换成对象 const x2js = new X2JS(); let xmlObj = x2js.xml_str2json(xmlStr); xmlObj = JSON.parse(util.restoreXMLEntity(JSON.stringify(xmlObj))); if (!xmlObj) { throw '无有效数据。'; } xmlObjMap[fileName] = xmlObj; } //提取数据 return extractProject(xmlObjMap); }; // 接受上传的文件类型(不同的省份可以上传的文件不同) const accept = ['.zip', '.cos']; return { accept, extractData, transformData, } })();