|  | @@ -56,6 +56,20 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |          // 费率、指数、比例(%)类小数精度
 | 
	
		
			
				|  |  |          RATE: 3,
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | +    // 根据上方精度要求得到的项目属性,小数位数的值
 | 
	
		
			
				|  |  | +    const tenderPropertyDecimal = {
 | 
	
		
			
				|  |  | +        bills: { unitPrice: Decimal.FEE, totalPrice: Decimal.FEE },
 | 
	
		
			
				|  |  | +        ration: { quantity: Decimal.QUANTITY, unitPrice: Decimal.FEE, totalPrice: Decimal.FEE },
 | 
	
		
			
				|  |  | +        glj: { quantity: Decimal.GLJ, unitPriceHasMix: Decimal.FEE, unitPrice: Decimal.FEE },
 | 
	
		
			
				|  |  | +        feeRate: Decimal.RATE,
 | 
	
		
			
				|  |  | +        quantity_detail: 4,
 | 
	
		
			
				|  |  | +        material: 5,//三材系数
 | 
	
		
			
				|  |  | +        process: 6
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const tenderPropertyBillsQuantityDecimal = Decimal.QUANTITY;
 | 
	
		
			
				|  |  | +    // 工程量表达式相关
 | 
	
		
			
				|  |  | +    const GCLMXHj = 'GCLMXHJ';
 | 
	
		
			
				|  |  | +    const QDL = 'QDL';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* 
 | 
	
		
			
				|  |  |       * 从导入的xml文件中提取有用的数据
 | 
	
	
		
			
				|  | @@ -74,7 +88,7 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              name: getValue(projectSrc, ['_Name']),
 | 
	
		
			
				|  |  |              engs: extractEngs(projectSrc, xmlObjMap),
 | 
	
		
			
				|  |  |              property: {
 | 
	
		
			
				|  |  | -                compilationIllustrationProject: getValue(projectSrc, ['_Explains'])
 | 
	
		
			
				|  |  | +                compilationIllustration: getValue(projectSrc, ['_Explains'])
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              basicInformation: extractBasicInfo(projectSrc)
 | 
	
		
			
				|  |  |          };
 | 
	
	
		
			
				|  | @@ -181,6 +195,7 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                  projType: projectType.Tender,
 | 
	
		
			
				|  |  |                  name: getValue(src, ['_Name']),
 | 
	
		
			
				|  |  |                  code: getValue(src, ['_Number']),
 | 
	
		
			
				|  |  | +                compilationIllustration: getValue(src, ['_Explains']),
 | 
	
		
			
				|  |  |                  engineering: getValue(src, ['_ProjectType']),
 | 
	
		
			
				|  |  |                  projectFeature: extractProjectFeature(src),
 | 
	
		
			
				|  |  |                  workSummary: extractWorkSummary(src),
 | 
	
	
		
			
				|  | @@ -293,15 +308,19 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              jobContent: getJobContent(workElementSrc),
 | 
	
		
			
				|  |  |              unit: getValue(workElementSrc, ['_Unit']),
 | 
	
		
			
				|  |  |              quantity: getValue(workElementSrc, ['_Quantity']),
 | 
	
		
			
				|  |  | -            feeRate: getValue(workElementSrc, ['_Rate']),
 | 
	
		
			
				|  |  |              mainBills: getBool(getValue(workElementSrc, ['_Major'])),
 | 
	
		
			
				|  |  |              feeCode: getValue(workElementSrc, ['_Code']),
 | 
	
		
			
				|  |  |              remark: getValue(workElementSrc, ['_Remark']),
 | 
	
		
			
				|  |  | +            quantityDetails: extractQuantityDetails(workElementSrc),
 | 
	
		
			
				|  |  |              rations: extractRations(workElementSrc)
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          if (type === billType.BILL) {
 | 
	
		
			
				|  |  | -            // 分项不需要基数
 | 
	
		
			
				|  |  | +            // 分项不需要基数、费率
 | 
	
		
			
				|  |  |              bills.calcBase = getValue(workElementSrc, ['_QtyFormula']);
 | 
	
		
			
				|  |  | +            const feeRate = getValue(workElementSrc, ['_Rate']);
 | 
	
		
			
				|  |  | +            if (+feeRate) {
 | 
	
		
			
				|  |  | +                bills.feeRate = feeRate;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // 投标和控制价,需要导入最高限价
 | 
	
		
			
				|  |  |          if ([FileKind.tender, FileKind.control].includes(importFileKind)) {
 | 
	
	
		
			
				|  | @@ -369,6 +388,15 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              }));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    // 提取工程量明细(清单、定额底下都可能会有)
 | 
	
		
			
				|  |  | +    function extractQuantityDetails(src) {
 | 
	
		
			
				|  |  | +        return arrayValue(src, ['ExpressElement']).map(itemSrc => ({
 | 
	
		
			
				|  |  | +            seq: getValue(itemSrc, ['_OrderNumber']),
 | 
	
		
			
				|  |  | +            regex: getValue(itemSrc, ['_Express']),
 | 
	
		
			
				|  |  | +            result: getValue(itemSrc, ['_Quantity']),
 | 
	
		
			
				|  |  | +            isSummation: +getValue(itemSrc, ['_Kind'])
 | 
	
		
			
				|  |  | +        }));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      // 提取定额
 | 
	
		
			
				|  |  |      function extractRations(workElementSrc) {
 | 
	
		
			
				|  |  |          if (importFileKind !== FileKind.tender) {
 | 
	
	
		
			
				|  | @@ -458,6 +486,7 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              const feesFromCalcItem = getFeesFromCalculationOfItem(rationSrc);
 | 
	
		
			
				|  |  |              ration.fees = mergeFees(fees, feesFromCalcItem);
 | 
	
		
			
				|  |  |              ration.rationGLJs = extractRationGLJs(rationSrc);
 | 
	
		
			
				|  |  | +            ration.quantityDetails = extractQuantityDetails(rationSrc);
 | 
	
		
			
				|  |  |              return ration;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -834,7 +863,10 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              gljLibIDs: tenderData.gljLibIDs,
 | 
	
		
			
				|  |  |              shareInfo: []
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | -        transformedTender.property.gljAdjustType = getAdjustType(tenderData)
 | 
	
		
			
				|  |  | +        transformedTender.property.compilationIllustration = tenderData.compilationIllustration;
 | 
	
		
			
				|  |  | +        transformedTender.property.gljAdjustType = getAdjustType(tenderData);
 | 
	
		
			
				|  |  | +        transformedTender.property.decimal = tenderPropertyDecimal;
 | 
	
		
			
				|  |  | +        transformedTender.property.billsQuantityDecimalValue = tenderPropertyBillsQuantityDecimal;
 | 
	
		
			
				|  |  |          detailData.tender = transformedTender;
 | 
	
		
			
				|  |  |          return detailData;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -862,7 +894,6 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 合并清单,将提取出来的清单相关数据,合并进项目清单(模板)
 | 
	
		
			
				|  |  |      function mergeBills(tenderData, billsTemplate) {
 | 
	
		
			
				|  |  | -        debugger;
 | 
	
		
			
				|  |  |          const mergedBills = [...billsTemplate];
 | 
	
		
			
				|  |  |          const roots = billsTemplate.filter(bills => bills.ParentID === -1);
 | 
	
		
			
				|  |  |          let lastRoot = roots.find(root => root.NextSiblingID === -1);
 | 
	
	
		
			
				|  | @@ -924,6 +955,7 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |          // 合并大项费用
 | 
	
		
			
				|  |  |          function mergeWorkSummary(workSummary) {
 | 
	
		
			
				|  |  |              // 首层数据与清单模板根据费用字典进行匹配,匹配到的则赋值一些属性,匹配不到则将其及其所有子数据插入到模板最末大项费用
 | 
	
		
			
				|  |  | +            debugger;
 | 
	
		
			
				|  |  |              workSummary.forEach(summaryBills => {
 | 
	
		
			
				|  |  |                  const matched = roots.find(root => FlagFeeCodeMap[getFlag(root)] === summaryBills.feeCode);
 | 
	
		
			
				|  |  |                  if (matched) {
 | 
	
	
		
			
				|  | @@ -948,13 +980,13 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |          // 合并措施项目
 | 
	
		
			
				|  |  |          function mergeCSXM(csxmSrc) {
 | 
	
		
			
				|  |  |              const fixedBills = billsTemplate.find(bills => getFlag(bills) === fixedFlag.MEASURE);
 | 
	
		
			
				|  |  | -            fixedBills.fees = csxmSrc.fees;
 | 
	
		
			
				|  |  | +            fixedBills.fees = mergeFees(fixedBills.fees, csxmSrc.fees);
 | 
	
		
			
				|  |  |              mergeitems(fixedBills, csxmSrc.items);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // 合并其他项目
 | 
	
		
			
				|  |  |          function mergeOther(otherSrc) {
 | 
	
		
			
				|  |  |              const fixedBills = billsTemplate.find(bills => getFlag(bills) === fixedFlag.OTHER);
 | 
	
		
			
				|  |  | -            fixedBills.fees = otherSrc.fees;
 | 
	
		
			
				|  |  | +            fixedBills.fees = mergeFees(fixedBills.fees, otherSrc.fees);
 | 
	
		
			
				|  |  |              // 合并其他项目费
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // SundryCosts其他项目费会包含暂列金额等后续会再次出现的数据,因此合并SundryCosts的数据时,过滤掉一部分数据
 | 
	
	
		
			
				|  | @@ -1091,7 +1123,7 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                  const fee = getFee(bills.fees, ['common', 'totalFee']);
 | 
	
		
			
				|  |  |                  const feeRate = bills.feeRate && parseFloat(bills.feeRate) !== 0 ? parseFloat(bills.feeRate) : 0;
 | 
	
		
			
				|  |  |                  if (fee && parseFloat(fee) !== 0 && feeRate) {
 | 
	
		
			
				|  |  | -                    bills.calcBase = scMathUtil.roundForObj(parseFloat(fee) * 100 / feeRate, 2);
 | 
	
		
			
				|  |  | +                    bills.calcBase = scMathUtil.roundForObj(parseFloat(fee) * 100 / feeRate, Decimal.FEE);
 | 
	
		
			
				|  |  |                  } else {
 | 
	
		
			
				|  |  |                      bills.calcBase = fee !== '0' ? fee : '';
 | 
	
		
			
				|  |  |                  }
 | 
	
	
		
			
				|  | @@ -1109,6 +1141,10 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 转换清单
 | 
	
		
			
				|  |  |      function transformBills(tenderData, billsTemplate) {
 | 
	
		
			
				|  |  | +        const rst = {
 | 
	
		
			
				|  |  | +            bills: [],
 | 
	
		
			
				|  |  | +            billsQuantityDetails: []
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  |          const billsData = mergeBills(tenderData, billsTemplate);
 | 
	
		
			
				|  |  |          setupFeeCode(billsData);
 | 
	
		
			
				|  |  |          transformCalcBase(billsData);
 | 
	
	
		
			
				|  | @@ -1128,8 +1164,9 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  } else {
 | 
	
		
			
				|  |  |                      // 综合合价的小数位数
 | 
	
		
			
				|  |  | -                    const totalFeeDecimal = totalFee.match(/\.\d+/);
 | 
	
		
			
				|  |  | -                    unitFee = scMathUtil.roundForObj(totalFee / bills.quantity, totalFeeDecimal ? totalFeeDecimal[0] : 0);
 | 
	
		
			
				|  |  | +                    //const totalFeeDecimal = totalFee.match(/\.\d+/);
 | 
	
		
			
				|  |  | +                    //unitFee = scMathUtil.roundForObj(totalFee / bills.quantity, totalFeeDecimal ? totalFeeDecimal[0] : 0);
 | 
	
		
			
				|  |  | +                    unitFee = scMathUtil.roundForObj(totalFee / bills.quantity, Decimal.FEE);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  const commonFee = bills.fees.find(fee => fee.fieldName === 'common');
 | 
	
		
			
				|  |  |                  if (commonFee) {
 | 
	
	
		
			
				|  | @@ -1137,10 +1174,26 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              bills.projectID = tenderData.ID;
 | 
	
		
			
				|  |  | -            bills.quantityEXP = bills.quantity;
 | 
	
		
			
				|  |  | -            // TODO 删除items rations feeCode
 | 
	
		
			
				|  |  | +            // 工程量明细
 | 
	
		
			
				|  |  | +            transformQuantityDetails(tenderData.ID, bills.quantityDetails, bills.ID, 'billID');
 | 
	
		
			
				|  |  | +            bills.quantityEXP = bills.quantityDetails && bills.quantityDetails.length ? GCLMXHj : bills.quantity;
 | 
	
		
			
				|  |  | +            if (bills.quantityDetails) {
 | 
	
		
			
				|  |  | +                rst.billsQuantityDetails.push(...bills.quantityDetails);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            rst.bills.push(bills);
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -        return billsData;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return rst;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // 转换工程量明细数据
 | 
	
		
			
				|  |  | +    function transformQuantityDetails(tenderID, quantityDetails, refID, typeKey) {
 | 
	
		
			
				|  |  | +        if (quantityDetails) {
 | 
	
		
			
				|  |  | +            quantityDetails.forEach(item => {
 | 
	
		
			
				|  |  | +                item.ID = uuid.v1();
 | 
	
		
			
				|  |  | +                item[typeKey] = refID; // billID、rationID
 | 
	
		
			
				|  |  | +                item.projectID = tenderID;
 | 
	
		
			
				|  |  | +            }); 
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 转换人材机汇总相关数据(人材机汇总、承包人材料、评标材料、暂估价材料、组成物、单价文件)
 | 
	
		
			
				|  |  |      function transformGLJList(tenderData, IDPlaceholder, projectGLJMap) {
 | 
	
	
		
			
				|  | @@ -1184,7 +1237,6 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                  rst.projectGLJ.push(projectGLJ);
 | 
	
		
			
				|  |  |                  // 单价文件数据:
 | 
	
		
			
				|  |  |                  rst.unitPrice.push(generateUnitPrice(projectGLJ));
 | 
	
		
			
				|  |  | -                // TODO 删除ratios
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // 转换与项目人材机关联的材料
 | 
	
	
		
			
				|  | @@ -1261,7 +1313,8 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |          const rst = {
 | 
	
		
			
				|  |  |              ration: [],
 | 
	
		
			
				|  |  |              rationGLJ: [],
 | 
	
		
			
				|  |  | -            rationCoe: []
 | 
	
		
			
				|  |  | +            rationCoe: [],
 | 
	
		
			
				|  |  | +            rationQuantityDetails: []
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          billsData
 | 
	
		
			
				|  |  |              .filter(bills => bills.rations && bills.rations.length)
 | 
	
	
		
			
				|  | @@ -1273,12 +1326,17 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                      ration.projectID = tenderData.ID;
 | 
	
		
			
				|  |  |                      ration.billsItemID = bills.ID;
 | 
	
		
			
				|  |  |                      ration.contain = getContain(bills, ration);
 | 
	
		
			
				|  |  | +                    // 工程量明细
 | 
	
		
			
				|  |  | +                    transformQuantityDetails(tenderData.ID, ration.quantityDetails, ration.ID, 'rationID');
 | 
	
		
			
				|  |  | +                    ration.quantityEXP = getQuantityEXP(bills, ration);
 | 
	
		
			
				|  |  | +                    if (ration.quantityDetails) {
 | 
	
		
			
				|  |  | +                        rst.rationQuantityDetails.push(...ration.quantityDetails);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  |                      rst.ration.push(ration);
 | 
	
		
			
				|  |  |                      // 定额人材机
 | 
	
		
			
				|  |  |                      rst.rationGLJ.push(...transformRationGLJs(bills, ration));
 | 
	
		
			
				|  |  |                      // 定额系数
 | 
	
		
			
				|  |  |                      rst.rationCoe.push(generateRationCoe(ration));
 | 
	
		
			
				|  |  | -                    // TODO 删除rationGljs
 | 
	
		
			
				|  |  |                  });
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          return rst;
 | 
	
	
		
			
				|  | @@ -1336,6 +1394,24 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |                  option_list: []
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // 获取定额的工程量表达式
 | 
	
		
			
				|  |  | +        function getQuantityEXP(bills, ration) {
 | 
	
		
			
				|  |  | +            if (ration.quantityDetails && ration.quantityDetails.length) {
 | 
	
		
			
				|  |  | +                return GCLMXHj;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // 定额根单位与清单根单位相同,则定额工程量表达式为QDL;否则定额工程量表达式为:定额工程量 * 定额单位量词
 | 
	
		
			
				|  |  | +            // eg: 清单单位:m  定额单位:100m
 | 
	
		
			
				|  |  | +            const reg = /\d+(\D+.*)/;
 | 
	
		
			
				|  |  | +            const billsRootUnit = bills.unit && bills.unit.replace(reg, '$1') || '';
 | 
	
		
			
				|  |  | +            const rationRootUnit = ration.unit && ration.unit.replace(reg, '$1') || '';
 | 
	
		
			
				|  |  | +            if (billsRootUnit === rationRootUnit) {
 | 
	
		
			
				|  |  | +                return QDL;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            const numReg = /(\d+)\D+.*/;
 | 
	
		
			
				|  |  | +            const num = ration.unit && ration.unit.replace(numReg, '$1') || '1';
 | 
	
		
			
				|  |  | +            return ration.quantity * num;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 删除一些无用属性,减少通信数据量
 | 
	
		
			
				|  |  |      function clean(detailData) {
 | 
	
	
		
			
				|  | @@ -1344,8 +1420,8 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |              ration,
 | 
	
		
			
				|  |  |              projectGLJ
 | 
	
		
			
				|  |  |          } = detailData;
 | 
	
		
			
				|  |  | -        bills.forEach(item => delete item.items && delete item.rations && delete item.feeCode);
 | 
	
		
			
				|  |  | -        ration.forEach(item => delete item.rationGLJs);
 | 
	
		
			
				|  |  | +        bills.forEach(item => delete item.items && delete item.rations && delete item.feeCode && delete item.quantityDetails);
 | 
	
		
			
				|  |  | +        ration.forEach(item => delete item.rationGLJs && delete item.quantityDetails);
 | 
	
		
			
				|  |  |          projectGLJ.forEach(item => delete item.ratios);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 需要给清单、定额价格字段赋上调价数据,不然打开项目后会被重算: project_view.js -> loadProjectData方法内
 | 
	
	
		
			
				|  | @@ -1366,14 +1442,22 @@ const importXML = (() => {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      // 转换详细的项目数据,清单、定额、定额人材机、项目人材机、单价文件等
 | 
	
		
			
				|  |  |      function transformDetail(tenderData, IDPlaceholder, billsTemplate) {
 | 
	
		
			
				|  |  | -        const bills = transformBills(tenderData, billsTemplate);
 | 
	
		
			
				|  |  | +        const { bills, billsQuantityDetails } = transformBills(tenderData, billsTemplate);
 | 
	
		
			
				|  |  |          // 转换定额的处理依赖转换后的项目人材机数据,因此需要先转换项目人材机相关的数据
 | 
	
		
			
				|  |  |          const projectGLJMap = {};
 | 
	
		
			
				|  |  |          const relatedljGLJData = transformGLJList(tenderData, IDPlaceholder, projectGLJMap);
 | 
	
		
			
				|  |  | -        const relatedRationData = transformRations(tenderData, bills, projectGLJMap);
 | 
	
		
			
				|  |  | +        const {
 | 
	
		
			
				|  |  | +            ration,
 | 
	
		
			
				|  |  | +            rationGLJ,
 | 
	
		
			
				|  |  | +            rationCoe,
 | 
	
		
			
				|  |  | +            rationQuantityDetails
 | 
	
		
			
				|  |  | +        } = transformRations(tenderData, bills, projectGLJMap);
 | 
	
		
			
				|  |  |          const detailData = {
 | 
	
		
			
				|  |  |              bills,
 | 
	
		
			
				|  |  | -            ...relatedRationData,
 | 
	
		
			
				|  |  | +            ration,
 | 
	
		
			
				|  |  | +            rationGLJ,
 | 
	
		
			
				|  |  | +            rationCoe,
 | 
	
		
			
				|  |  | +            quantityDetails: [...billsQuantityDetails, ... rationQuantityDetails],
 | 
	
		
			
				|  |  |              ...relatedljGLJData
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          clean(detailData);
 |