|
|
@@ -1,3 +1,4 @@
|
|
|
+
|
|
|
/*
|
|
|
* @Descripttion: 导入通用代码
|
|
|
* @Author: vian
|
|
|
@@ -156,31 +157,7 @@ const INTERFACE_EXPORT_BASE = (() => {
|
|
|
return rst;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * 递归获取相关数据,eg:获取组织措施清单下的所有子清单,该子清单们可能由分类及公式措施项各种组合组成。(参考调用处)
|
|
|
- * @param {Object}src(数据源) {Array}fields(二维数组,数组里的成员由需要取的字段组成)
|
|
|
- * eg: ['组织措施分类'], ['公式计算措施项'],该层数据可能由组织措施分类 或 公式计算措施项组成 (同层不可同时存在)
|
|
|
- * {Function} 获得源数据后,需要提取的数据方法
|
|
|
- * @return {Array}
|
|
|
- * */
|
|
|
- function getItemsRecur(src, fields, extractFuc) {
|
|
|
- let itemsSrc = [];
|
|
|
- let curField = [''];
|
|
|
- for (const field of fields) {
|
|
|
- itemsSrc = arrayValue(src, field);
|
|
|
- if (itemsSrc.length) {
|
|
|
- curField = field;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return itemsSrc.map(itemSrc => {
|
|
|
- const obj = extractFuc(itemSrc, curField);
|
|
|
- obj.items = getItemsRecur(itemSrc, fields, extractFuc);
|
|
|
- return obj;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // 递归获取相关数据,与上方的方法不同的点在:同层可能出现不同节点,上方方法暂时不取消(防止bug)
|
|
|
+ // 递归获取相关数据,(同层可以出现不同节点)
|
|
|
// fields内字段的顺序即决定了提取数据类型的顺序,如fields = [['gruop'], ['item']],则提取的数据同层中group数据在item数据之前
|
|
|
function extractItemsRecur(src, fields, extractFuc) {
|
|
|
const rst = [];
|
|
|
@@ -188,8 +165,8 @@ const INTERFACE_EXPORT_BASE = (() => {
|
|
|
const itemsSrc = arrayValue(src, field);
|
|
|
if (itemsSrc.length) {
|
|
|
const items = itemsSrc.map(itemSrc => {
|
|
|
- const obj = extractFuc(itemSrc, field);
|
|
|
- obj.items = extractItemsRecur(itemSrc, fields, extractFuc);
|
|
|
+ const obj = extractFuc(itemSrc, field[0]);
|
|
|
+ obj.children = extractItemsRecur(itemSrc, fields, extractFuc);
|
|
|
return obj;
|
|
|
});
|
|
|
rst.push(...items);
|
|
|
@@ -210,14 +187,152 @@ const INTERFACE_EXPORT_BASE = (() => {
|
|
|
mergeDataRecur,
|
|
|
getFlag,
|
|
|
getBool,
|
|
|
- getItemsRecur,
|
|
|
extractItemsRecur,
|
|
|
});
|
|
|
|
|
|
+ /**
|
|
|
+ * 合并基本信息或工程特征
|
|
|
+ * @param {Array} source - 提取的数据
|
|
|
+ * @param {Array} target - 模板数据
|
|
|
+ * @return {Array}
|
|
|
+ */
|
|
|
+ function mergeInfo(source, target) {
|
|
|
+ source.forEach(item => mergeChild(item, target));
|
|
|
+ return target;
|
|
|
+
|
|
|
+ function mergeChild(item, target) {
|
|
|
+ for (const child of target) {
|
|
|
+ if (child.key === item.key) {
|
|
|
+ child.value = item.value;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (child.items && child.items.length) {
|
|
|
+ const rst = mergeChild(item, child.items);
|
|
|
+ if (rst) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理清单
|
|
|
+ function handleBills(tenderBills, tenderID, billsTemplate) {
|
|
|
+ // 给清单设置ID、projectID
|
|
|
+ const rowCodeData = []; // 行号数据,用于转换行引用
|
|
|
+ const toBeTransformBills = []; // 待转换的清单
|
|
|
+ function setBills(bills) {
|
|
|
+ bills.forEach(child => {
|
|
|
+ child.ID = uuid.v1();
|
|
|
+ child.projectID = tenderID;
|
|
|
+ if (child.rowCode) {
|
|
|
+ rowCodeData.push({ reg: new RegExp(`\\b${child.rowCode}\\b`, 'g'), ID: child.ID });
|
|
|
+ }
|
|
|
+ if (child.calcBase) {
|
|
|
+ toBeTransformBills.push(child);
|
|
|
+ }
|
|
|
+ if (child.children && child.children.length) {
|
|
|
+ setBills(child.children);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ setBills(tenderBills);
|
|
|
+ // 转换计算基数,将行引用转换为ID引用
|
|
|
+ toBeTransformBills.forEach(bills => {
|
|
|
+ rowCodeData.forEach(({ reg, ID }) => {
|
|
|
+ bills.calcBase = bills.calcBase.replace(reg, `@${ID}`);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ // 将提取的清单数据合并进清单模板数据
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理单位工程数据
|
|
|
+ function handleTenderData(tenders, templateData) {
|
|
|
+ tenders.forEach((tender, index) => {
|
|
|
+ tender.compilation = compilationData._id;
|
|
|
+ tender.userID = userID;
|
|
|
+ tender.ID = templateData.projectBeginID + index + 1;
|
|
|
+ tender.ParentID = templateData.projectBeginID;
|
|
|
+ tender.NextSiblingID = index === tenders.length - 1 ? -1 : templateData.projectBeginID + index + 2;
|
|
|
+ tender.projType = projectType.tender;
|
|
|
+ const featureTarget = _.cloneDeep(templateData.feature); // 必须拷贝出一份新数据,否则会被下一个单位工程覆盖
|
|
|
+ const rationValuationData = JSON.parse(rationValuation)[0];
|
|
|
+ const engineeringList = rationValuationData.engineering_list;
|
|
|
+ const engineeringLib = engineeringList.find(item => item.lib.visible);
|
|
|
+ if (!engineeringLib) {
|
|
|
+ throw '不存在可用工程专业。';
|
|
|
+ }
|
|
|
+ const taxData = engineeringLib.lib.tax_group[0];
|
|
|
+ tender.property = {
|
|
|
+ rootProjectID: tender.ParentID,
|
|
|
+ region: '全省',
|
|
|
+ engineering_id: engineeringLib.engineering_id,
|
|
|
+ engineeringName: engineeringLib.lib.name,
|
|
|
+ feeStandardName: engineeringLib.lib.feeName,
|
|
|
+ engineering: engineeringLib.engineering,
|
|
|
+ isInstall: engineeringLib.lib.isInstall,
|
|
|
+ projectEngineering: engineeringLib.lib.projectEngineering,
|
|
|
+ valuation: rationValuationData.id,
|
|
|
+ valuationName: rationValuationData.name,
|
|
|
+ valuationType: commonConstants.ValuationType.BOQ, // 必为工程量清单
|
|
|
+ boqType: commonConstants.BOQType.BID_SUBMISSION, // 导入后必为投标
|
|
|
+ taxType: taxData.taxType,
|
|
|
+ projectFeature: mergeInfo(tender.feature, featureTarget),
|
|
|
+ featureLibID: engineeringLib.lib.feature_lib[0] && engineeringLib.lib.feature_lib[0].id || '',
|
|
|
+ calcProgram: { name: taxData.program_lib.name, id: taxData.program_lib.id },
|
|
|
+ colLibID: taxData.col_lib.id,
|
|
|
+ templateLibID: taxData.template_lib.id,
|
|
|
+ unitPriceFile: { name: tender.name, id: '' }, // 新建单价文件
|
|
|
+ feeFile: { name: tender.name, id: `newFeeRate@@${taxData.fee_lib.id}` } // 新建费率文件
|
|
|
+ };
|
|
|
+ delete tender.feature;
|
|
|
+ handleBills(tender.bills, tender.ID, templateData.bills);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将接口中提取出来数据转换成可入库的有效数据
|
|
|
+ * 因为无法保证这一套逻辑能不能兼容以后的所有接口,因此提取数据与标准数据模板的合并放在前端进行。
|
|
|
+ * 当统一逻辑无法满足某一接口时,接口可以根据标准模板数据自行进行相关处理。
|
|
|
+ * @param {Object} importData - 各接口从xml提取出来的数据
|
|
|
+ * @return {Promise<Object>}
|
|
|
+ */
|
|
|
+ async function handleImportData(importData) {
|
|
|
+ const valuationID = compilationData.ration_valuation[0].id;
|
|
|
+ if (!Array.isArray(importData.tenders) && !importData.tenders.length) {
|
|
|
+ throw '导入的文件中不存在有效的标段数据。';
|
|
|
+ }
|
|
|
+ const projectCount = 1 + importData.tenders.length;
|
|
|
+ const templateData = await ajaxPost('/pm/api/getImportTemplateData', { user_id: userID, valuationID, projectCount });
|
|
|
+ if (!templateData) {
|
|
|
+ throw '无法获取有效模板数据。';
|
|
|
+ }
|
|
|
+ console.log(templateData);
|
|
|
+ // 处理建设项目数据
|
|
|
+ importData.compilation = compilationData._id;
|
|
|
+ importData.userID = userID;
|
|
|
+ importData.ID = templateData.projectBeginID;
|
|
|
+ const { parentProjectID, preProjectID, nextProjectID } = projTreeObj.getRelProjectID(projTreeObj.tree.selected);
|
|
|
+ importData.ParentID = parentProjectID;
|
|
|
+ importData.preID = preProjectID;
|
|
|
+ importData.NextSiblingID = nextProjectID;
|
|
|
+ importData.projType = projectType.project;
|
|
|
+ importData.proprty = {
|
|
|
+ valuationType: commonConstants.ValuationType.BOQ, // 必为工程量清单
|
|
|
+ boqType: commonConstants.BOQType.BID_SUBMISSION, // 导入后必为投标
|
|
|
+ basicInformation: mergeInfo(importData.info, templateData.basicInfo) // 将提取的基本信息数据与标准基本信息数据进行合并(目前只赋值,没有匹配到的不追加)
|
|
|
+ };
|
|
|
+ delete importData.info;
|
|
|
+ // 处理单位工程数据
|
|
|
+ handleTenderData(importData.tenders, templateData);
|
|
|
+
|
|
|
+ console.log(importData);
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* 读取文件转换为utf-8编码的字符串
|
|
|
- * @param {Blob}file
|
|
|
+ * @param {Blob} file
|
|
|
* @return {Promise}
|
|
|
* */
|
|
|
function readAsTextSync(file) {
|
|
|
@@ -238,17 +353,10 @@ const INTERFACE_EXPORT_BASE = (() => {
|
|
|
* @param {Function} entryFunc - 各导入接口提取导入数据方法
|
|
|
* @param {File} file - 导入的文件
|
|
|
* @param {String} areaKey - 地区标识,如:'安徽@马鞍山'
|
|
|
- * @param {String} feeRateStandard - 导入接口地区对应的费率标准名称
|
|
|
* @param {Boolean} escape - 是否需要避免xml中的实体字符转换
|
|
|
* @return {Promise<Object>}
|
|
|
*/
|
|
|
- async function extractImportData(entryFunc, file, areaKey, feeRateStandard, escape = false) {
|
|
|
- const valuationID = compilationData.ration_valuation[0].id;
|
|
|
- const templateData = await ajaxPost('/pm/api/getImportTemplateData', { user_id: userID, valuationID, feeRateStandard });
|
|
|
- if (!templateData) {
|
|
|
- throw '无法获取有效模板数据。';
|
|
|
- }
|
|
|
- console.log(templateData);
|
|
|
+ async function extractImportData(entryFunc, file, areaKey, escape = false) {
|
|
|
// 将二进制文件转换成字符串
|
|
|
let xmlStr = await readAsTextSync(file);
|
|
|
if (escape) {
|
|
|
@@ -263,7 +371,8 @@ const INTERFACE_EXPORT_BASE = (() => {
|
|
|
if (!xmlObj) {
|
|
|
throw '无有效数据。';
|
|
|
}
|
|
|
- return await entryFunc(areaKey, xmlObj, templateData);
|
|
|
+ const importData = await entryFunc(areaKey, xmlObj);
|
|
|
+ await handleImportData(importData);
|
|
|
}
|
|
|
|
|
|
return {
|