Bläddra i källkod

Merge branch 'temp' into develop

xujunjie 1 år sedan
förälder
incheckning
3958fce399

+ 12 - 46
src/pages/Detail/CommitAuditModal.js

@@ -1,4 +1,4 @@
-import React, {useEffect, useState, useRef, useMemo, useCallback} from 'react';
+import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react';
 import '@ant-design/compatible/assets/index.css';
 import {
   Modal,
@@ -43,6 +43,7 @@ import AttachmentTable from '@/components/AttachmentTable';
 import {getToken} from '@/utils/utils';
 import LuckyExcel from 'luckyexcel';
 import DDComponents from "@/components/DDComponents";
+import uploadExcelByUrl from '@/utils/uploadExcelByUrl';
 
 const {TextArea} = Input;
 const {Option} = Select;
@@ -63,6 +64,7 @@ function CommitAuditModal(props) {
     luckysheet,
     userList,
     templateId,
+    projectList,
     OSSData,
   } = props;
   // console.log(loading);
@@ -158,6 +160,8 @@ function CommitAuditModal(props) {
     if (res.data) {
       const formList = JSON.parse(res.data.json);
       setApprovalProcess(formList.approvalProcess || {});
+      const prevFormData = JSON.parse(formList.formList?.[0] || '{}');
+      setFormComponentValues(prevFormData);
       return formList;
     }
   };
@@ -543,7 +547,10 @@ function CommitAuditModal(props) {
         next_template_id: version.template_id,
       };
       if (serviceNode.node_type_psr == 3 || serviceNode.node_type_psr == 4) {
-        params.data = await uploadExcelByUrl(serviceNode.node_type_psr, version.id);
+        let project = projectList.find(item => item.id == version?.project_id);
+        let projectName = project?.project_name || '';
+        let sheetData = await uploadExcelByUrl(serviceNode.node_type_psr, version.id, projectName);
+        params.data = JSON.stringify(sheetData);
       }
       // params.data = await uploadExcelByUrl(3, version.id);
       console.log(params);
@@ -730,53 +737,12 @@ function getDataValue(item) {
   return arr;
 }
 
-const uploadExcelByUrl = (nodeType, versionId) => {
-  const TEMPLATE_URL =
-    'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-06-29/ed0d5dcd-6ce0-40df-9d17-a1f69245dbb9.xlsx';
-  const TEMPLATE_URL2 =
-    'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-06-29/431733cd-0abc-4a68-a439-d24c466e9845.xlsx';
-
-  return new Promise((reslove, reject) => {
-    LuckyExcel.transformExcelToLuckyByUrl(
-      nodeType == 3 ? TEMPLATE_URL : TEMPLATE_URL2,
-      '模板.xlsx',
-      async (exportJson, luckysheetfile) => {
-        let [record] = await getExcel(versionId);
-
-        let len = exportJson.sheets.length;
-        const excelData = exportJson.sheets?.map(item => {
-          return {...item, order: Number(item.order)};
-        });
-        delete record.id;
-        record.order = len;
-        record.index = String(len);
-        record.status = '0';
-        record.name = '投标成本';
-        var res = [...excelData, record];
-        console.log(res);
-        reslove(JSON.stringify(res));
-      }
-    );
-  });
-};
-
-async function getExcel(gridKey) {
-  var formData = new FormData();
-  formData.append('gridKey', gridKey);
-  let res = await fetch(
-    `/api/v1/purchase/record/sheet?gridKey=${gridKey}&JWT-TOKEN=${getToken()}`,
-    {
-      method: 'POST',
-      body: formData,
-    }
-  ).then(response => response.text());
-  return JSON.parse(JSON.parse(res));
-}
-
-export default connect(({xflow, detail, user}) => ({
+export default connect(({ xflow, detail, user, list }) => ({
   flowDetail: xflow.flowDetail,
   versionList: detail.versionList,
   currentUser: user.currentUser,
   userList: user.list,
   OSSData: detail.OSSData,
+  // 隐患:刷新页面后将会丢失projectList
+  projectList: list?.project?.list || [],
 }))(CommitAuditModal);

+ 0 - 1
src/pages/Detail/CurrentInfo.js

@@ -7,7 +7,6 @@ function CurrentInfo(props) {
   const nodeId = version.template_node_id;
   if (!flowDetail?.nodes || !nodeId) return null;
   const node = flowDetail.nodes.find(item => item.Id == nodeId);
-  console.log(projectList);
 
   const projectName = useMemo(() => {
     let project = projectList.find(item => item.id == version?.project_id);

+ 2 - 6
src/pages/Detail/Index.js

@@ -7,13 +7,10 @@ import LuckySheet from './LuckySheet';
 import AuditModal from './AuditModal';
 // import CommentDrawer from './CommentDrawer';
 import RightDrawer from './RightDrawer';
-import CommitModal from './CommitModal';
 import CompareModal from './CompareModal';
 import ExportModal from './ExportModal';
 import FlowModal from './FlowModal';
-import HistoryModal from './HistoryModal';
 import TimeNode from './TimeNode';
-import FilesModal from './FilesModal';
 import VersionModal from './VersionModal';
 import CommitAuditModal from './CommitAuditModal';
 import CommentContent from '@/components/CommentContent';
@@ -36,9 +33,7 @@ import FormAndFilesNode from './FormAndFilesNode';
 import DropdownMenu from './DropdownMenu';
 import CurrentInfo from './CurrentInfo';
 import moment from 'moment';
-import { LocalStorage } from '@antv/x6';
-
-const LocalData = localStorage.luckysheet;
+import PsrControl from './PsrControl';
 
 function Detail(props) {
   const {
@@ -589,6 +584,7 @@ function Detail(props) {
           onChange={e => exportExcl(e.target.files)}
         />
       </div>
+      <PsrControl sheetRef={sheetRef} />
       <div style={{ display: 'flex' }}>
         <div
           className={styles.content}

+ 50 - 1
src/pages/Detail/LuckySheet.js

@@ -1,8 +1,9 @@
 import React from 'react';
-import { message } from 'antd';
+import { Button, message } from 'antd';
 import exportExcel, { getExcelBolob } from '@/utils/exportExcl';
 import LuckyExcel from 'luckyexcel';
 import { getToken, GetTokenFromUrl } from '@/utils/utils';
+import GoalSeek from '@/utils/GoalSeek';
 
 const hintText = '禁止编辑!请先点击编辑按钮。';
 const DIFF_COLOR = '#ff0000';
@@ -82,6 +83,7 @@ class LuckySheet extends React.Component {
       // forceCalculation: true,
       hook: {
         cellMousedown: (cell, position, sheet) => {
+          console.log(cell, position, sheet)
           onClickCell && onClickCell(cell, position, sheet);
         },
         cellPasteBefore: cell => {
@@ -614,6 +616,53 @@ class LuckySheet extends React.Component {
     return comment;
   }
 
+  async goalSeek(type, goal) {
+    let luckysheet = this.luckysheet;
+
+    const fn = function(x) {
+      return new Promise(resolve => {
+        luckysheet.setCellValue(9, 2, x.toFixed(4), {
+          order: 0,
+          success: () => {
+            luckysheet.refreshFormula(() => {
+              let row;
+              if (type == 1) {
+                row = 1;
+              } else if (type == 2) {
+                row = 4;
+              } else {
+                row = 5;
+              }
+              let data = luckysheet.getCellValue(row, 2, {
+                order: 0,
+              });
+              console.log(data);
+              resolve(data);
+            });
+          },
+        });
+      });
+    };
+    try {
+      let defaultValue = luckysheet.getCellValue(9, 2, {
+        order: 0,
+      });
+      const result = await GoalSeek({
+        goal,
+        fn,
+        fnParams: [defaultValue],
+        maxIterations: 1000,
+        maxStep: 0.03,
+        percentTolerance: 1,
+        independentVariableIdx: 0,
+      });
+      console.log(result);
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+
   render() {
     return (
       <iframe

+ 79 - 0
src/pages/Detail/PsrControl.js

@@ -0,0 +1,79 @@
+import { Button, Input, InputNumber, Select, Spin } from 'antd';
+import React, { useState } from 'react';
+
+const { Option } = Select;
+
+function PsrControl(props) {
+  const { sheetRef } = props;
+  const [value1, setValue1] = useState(0.15);
+  const [value2, setValue2] = useState(0.25);
+  const [value3, setValue3] = useState(14096800);
+  const [loading, setLoading] = useState(false);
+
+  const changeProjectType = type => {
+    sheetRef.current.luckysheet.setCellValue(101, 1, type, {
+      order: 0,
+    });
+    sheetRef.current.luckysheet.setCellFormat(101, 1, 'ct', { fa: 'General', t: 'g' });
+    sheetRef.current.luckysheet.refreshFormula();
+  };
+  const changeBiddingType = type => {
+    sheetRef.current.luckysheet.setCellValue(102, 1, type, {
+      order: 0,
+    });
+    sheetRef.current.luckysheet.setCellFormat(102, 1, 'ct', { fa: 'General', t: 'g' });
+    sheetRef.current.luckysheet.refreshFormula();
+  };
+
+  const goalSeek = (type, value) => {
+    setLoading(true);
+    try {
+      sheetRef.current.goalSeek(type, value);
+    } catch (error) {}
+    setLoading(false);
+  };
+
+  return (
+    <div style={{ marginBottom: 20 }}>
+      <Spin spinning={loading}>
+        <Input
+          value={value1}
+          style={{ width: 160, marginRight: 20 }}
+          onChange={e => setValue1(e.target.value)}
+          addonAfter={<a onClick={() => goalSeek(1, value1)}>净利率</a>}
+        />
+        <Input
+          value={value2}
+          style={{ width: 160, marginRight: 20 }}
+          onChange={e => setValue2(e.target.value)}
+          addonAfter={<a onClick={() => goalSeek(2, value2)}>毛利率</a>}
+        />
+        <Input
+          value={value3}
+          style={{ width: 220, marginRight: 20 }}
+          onChange={e => setValue3(e.target.value)}
+          addonAfter={<a onClick={() => goalSeek(3, value3)}>合同总价</a>}
+        />
+
+        <Select
+          placeholder="项目类别"
+          onChange={changeProjectType}
+          style={{ width: 120, marginRight: 20 }}
+        >
+          <Option value="UF">UF</Option>
+          <Option value="RO/NF">RO/NF</Option>
+          <Option value="UF&RO/NF">UF+RO/NF</Option>
+          <Option value="MBR">MBR</Option>
+          <Option value="其他">其他</Option>
+        </Select>
+        <Select placeholder="招标类型" onChange={changeBiddingType} style={{ width: 120 }}>
+          <Option value="货物招标">货物招标</Option>
+          <Option value="服务招标">服务招标</Option>
+          <Option value="工程招标">工程招标</Option>
+        </Select>
+      </Spin>
+    </div>
+  );
+}
+
+export default PsrControl;

+ 24 - 65
src/pages/Temp/index.js

@@ -5,52 +5,37 @@ import LuckyExcel from 'luckyexcel';
 import { Button, message } from 'antd';
 import { getToken } from '@/utils/utils';
 import moment from 'moment';
+import uploadExcelByUrl from '@/utils/uploadExcelByUrl';
 
 const TEMPLATE_URL =
-  'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/bom/635/%E5%90%88%E5%90%8C%E6%96%87%E4%BB%B6/%E6%8A%95%E6%A0%87%E6%A8%A1%E6%9D%BF.xlsx';
+  'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-06-29/ed0d5dcd-6ce0-40df-9d17-a1f69245dbb9.xlsx';
 
-const TEMPLATE_URL2 = 'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/public/bom/psr.xlsx';
+const TEMPLATE_URL2 =
+  'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/public/bom/ContractTemplate.xlsx';
 
 function Index(props) {
-  const { versionId = 2376 } = props;
+  const { versionId = 2554 } = props;
 
   const sheetRef = useRef();
   const luckysheetRef = useRef();
 
-  const uploadExcelByUrl = type => {
-    LuckyExcel.transformExcelToLuckyByUrl(
-      type == 1 ? TEMPLATE_URL : TEMPLATE_URL2,
-      '模板.xlsx',
-      async (exportJson, luckysheetfile) => {
-        // if (type == 2) initData(exportJson.sheets);
-        let [record] = await getExcel(versionId);
-
-        let len = exportJson.sheets.length;
-        record.order = len - 1;
-        record.index = len;
-        record.status = '0';
-
-        const data = [...exportJson.sheets, record];
-        console.log(data);
-
-        luckysheetRef.current.destroy();
-
-        luckysheetRef.current.create({
-          data,
-          lang: 'zh',
-          showinfobar: false,
-          showstatisticBar: false,
-          hook: {
-            cellMousedown: (cell, position, sheet) => {
-              console.log(cell, position, sheet);
-            },
-            cellUpdated: () => {
-              luckysheetRef.current.refreshFormula();
-            },
-          },
-        });
-      }
-    );
+  const onClick = async type => {
+    let data = await uploadExcelByUrl(type, versionId, 'test水厂');
+    luckysheetRef.current.destroy();
+    luckysheetRef.current.create({
+      data,
+      lang: 'zh',
+      showinfobar: false,
+      showstatisticBar: false,
+      hook: {
+        cellMousedown: (cell, position, sheet) => {
+          console.log(cell, position, sheet);
+        },
+        cellUpdated: () => {
+          luckysheetRef.current.refreshFormula();
+        },
+      },
+    });
   };
 
   const handleLoad = () => {
@@ -58,25 +43,12 @@ function Index(props) {
     luckysheetRef.current = contentWindow.luckysheet;
   };
 
-  const initData = sheets => {
-    let r = 5,
-      c = 12;
-    // let dateCell = sheets[3].celldata.find(item => item.r == 1 && item.c == 3);
-    let timer = sheets[3].celldata.filter(item => item.r == r && item.c >= c);
-    timer.forEach((item, index) => {
-      const cell = item.v;
-      
-      cell.f = `=EDATE(D2,${index})`;
-    });
-    console.log(timer);
-  };
-
   return (
     <div>
-      <Button type="primary" style={{ marginRight: 20 }} onClick={() => uploadExcelByUrl(1)}>
+      <Button type="primary" style={{ marginRight: 20 }} onClick={() => onClick(3)}>
         导入投标投标
       </Button>
-      <Button type="primary" onClick={() => uploadExcelByUrl(2)}>
+      <Button type="primary" onClick={() => onClick(4)}>
         导入合同模板
       </Button>
 
@@ -93,17 +65,4 @@ function Index(props) {
   );
 }
 
-async function getExcel(gridKey) {
-  var formData = new FormData();
-  formData.append('gridKey', gridKey);
-  let res = await fetch(
-    `/api/v1/purchase/record/sheet?gridKey=${gridKey}&JWT-TOKEN=${getToken()}`,
-    {
-      method: 'POST',
-      body: formData,
-    }
-  ).then(response => response.text());
-  return JSON.parse(JSON.parse(res));
-}
-
 export default Index;

+ 91 - 0
src/utils/GoalSeek.js

@@ -0,0 +1,91 @@
+const IsNanError = TypeError('resulted in NaN');
+const FailedToConvergeError = Error('failed to converge');
+const InvalidInputsError = Error('invalid inputs');
+
+export default async function GoalSeek({
+  fn,
+  fnParams,
+  percentTolerance,
+  customToleranceFn,
+  maxIterations,
+  maxStep,
+  goal,
+  independentVariableIdx,
+}) {
+  if (typeof customToleranceFn !== 'function') {
+    if (!percentTolerance) {
+      throw InvalidInputsError;
+    }
+  }
+  let g;
+  let y;
+  let y1;
+  let oldGuess;
+  let newGuess;
+  let res;
+  const absoluteTolerance = ((percentTolerance || 0) / 100) * goal;
+  // iterate through the guesses
+  for (let i = 0; i < maxIterations; i++) {
+    // define the root of the function as the error
+    res = await fn(...fnParams);
+    y = res - goal;
+    if (isNaN(y)) throw IsNanError;
+    // was our initial guess a good one?
+    if (typeof customToleranceFn !== 'function') {
+      if (Math.abs(y) <= Math.abs(absoluteTolerance)) return fnParams[independentVariableIdx];
+    } else {
+      if (customToleranceFn(res)) return fnParams[independentVariableIdx];
+    }
+    // set the new guess, correcting for maxStep
+    oldGuess = fnParams[independentVariableIdx];
+    newGuess = oldGuess + y;
+    if (Math.abs(newGuess - oldGuess) > maxStep) {
+      if (newGuess > oldGuess) {
+        newGuess = oldGuess + maxStep;
+      } else {
+        newGuess = oldGuess - maxStep;
+      }
+    }
+    fnParams[independentVariableIdx] = newGuess;
+    // re-run the fn with the new guess
+    y1 = (await fn(...fnParams)) - goal;
+    if (isNaN(y1)) throw IsNanError;
+    // calculate the error
+    g = (y1 - y) / y;
+    if (g === 0) g = 0.0001;
+    // set the new guess based on the error, correcting for maxStep
+    newGuess = oldGuess - y / g;
+    if (maxStep && Math.abs(newGuess - oldGuess) > maxStep) {
+      if (newGuess > oldGuess) {
+        newGuess = oldGuess + maxStep;
+      } else {
+        newGuess = oldGuess - maxStep;
+      }
+    }
+    fnParams[independentVariableIdx] = newGuess;
+  }
+  // done with iterations, and we failed to converge
+  throw FailedToConvergeError;
+}
+
+// const fn = (x, y) => x / y;
+// const fnParams = [2037375, 15897178];
+// const customToleranceFn = (x) => {
+//   return x < 1;
+// };
+
+// try {
+//   const result = goalSeek({
+//     fn,
+//     fnParams,
+//     customToleranceFn,
+//     maxIterations: 1000,
+//     maxStep: 0.01,
+//     goal: 0.15,
+//     independentVariableIdx: 0,
+//   });
+
+//   console.log(`result: ${result}`);
+// } catch (e) {
+//   console.log("error", e);
+// }

+ 220 - 0
src/utils/uploadExcelByUrl.js

@@ -0,0 +1,220 @@
+import LuckyExcel from 'luckyexcel';
+import { getToken } from '@/utils/utils';
+
+const uploadExcelByUrl = (nodeType, versionId, projectName) => {
+  const TEMPLATE_URL = 'https://gt-digitization.oss-cn-hangzhou.aliyuncs.com/public/bom/psr.xlsx';
+
+  return new Promise((resolve, reject) => {
+    LuckyExcel.transformExcelToLuckyByUrl(
+      TEMPLATE_URL,
+      '模板.xlsx',
+      async (exportJson, luckysheetfile) => {
+        let [record] = await getExcel(versionId);
+
+        let len = exportJson.sheets.length;
+        const excelData = exportJson.sheets;
+        delete record.id;
+        record.index = len + '_' + Math.floor(Math.random() * 100);
+        record.status = '0';
+        record.name = '清单';
+        // var sheets = [...excelData, record];
+        var res = [];
+        const category = getCategoryData(record);
+        // 处理Estimate表
+        // initEstimate(sheets[0], category);
+
+        // 处理psr预算
+        excelData[1].status = 1;
+        res.push(initPSR(excelData[1], category, projectName));
+
+        if (nodeType == 4) {
+          // 处理现金流
+          res.push(initActual(excelData[3], category, projectName));
+        }
+
+        res.push(record);
+
+        // 隐藏Estimate表
+        excelData[0].hide = 1;
+        excelData[0].status = 0;
+
+        res.push(excelData[0]);
+
+        resolve(res.map((item, index) => ({ ...item, order: index })));
+      }
+    );
+  });
+};
+
+async function getExcel(gridKey) {
+  var formData = new FormData();
+  formData.append('gridKey', gridKey);
+  let res = await fetch(
+    `/api/v1/purchase/record/sheet?gridKey=${gridKey}&JWT-TOKEN=${getToken()}`,
+    {
+      method: 'POST',
+      body: formData,
+    }
+  ).then(response => response.text());
+  return JSON.parse(JSON.parse(res));
+}
+
+function getCellValue(cell) {
+  let v = '';
+  if (cell.v) {
+    v = cell.v;
+  } else if (cell?.ct?.s) {
+    v = cell.ct.s.map(item => item.v).join('');
+  }
+  return v;
+}
+
+function formatNumber(str) {
+  const number = parseFloat(str);
+  if (!isNaN(number) && number % 1 !== 0) {
+    return number.toFixed(1);
+  }
+  return str;
+}
+// 根据清单获取表分类总价
+function getCategoryData(bom) {
+  let bomData = [],
+    bomTitle = {};
+  bom.celldata.forEach(item => {
+    let v = getCellValue(item.v);
+    if (item.r == 0) {
+      // 设置表头
+      bomTitle[item.c] = v;
+    } else {
+      let key = bomTitle[item.c];
+      if (!bomData[item.r - 1]) {
+        bomData[item.r - 1] = {};
+      }
+      bomData[item.r - 1][key] = v;
+    }
+  });
+  let category = {
+    'GT-UF膜': 0,
+    原平制造: 0,
+    其它膜: 0,
+    水泵: 0,
+    阀门: 0,
+    加药系统: 0,
+    过滤器: 0,
+    空压机: 0,
+    非标: 0,
+    仪表: 0,
+    电气自控: 0,
+    双胞胎硬件: 0,
+    材料: 0,
+    安装: 0,
+    土建: 0,
+    运输: 0,
+    其它: 0,
+  };
+  bomData.forEach(item => {
+    if (category.hasOwnProperty(item['类别'])) {
+      let price = parseFloat(item['总价(元)']);
+      if (isNaN(price)) return;
+      category[item['类别']] += price;
+    }
+  });
+  return category;
+}
+
+// 处理现金流表
+function initActual(actual, category, projectName) {
+  let actualCategory = [];
+  actual.celldata.forEach((item, i, celldata) => {
+    if (item.c == 0 && item.v?.v) {
+      // 处理序号转float出现多余小数的情况
+      item.v.v = formatNumber(item.v?.v);
+    }
+    if (item.c == 1 && item.r == 0) item.v.v = projectName;
+    // 清单分类的总价填入对应预算列
+    if (item.c == 2) {
+      // c=2 为名称列
+      let value = getCellValue(item.v);
+      // 判断该行是否为类型总列
+      if (category.hasOwnProperty(value)) {
+        // 名称后第三列为预算列
+        celldata[i + 3].v.v = category[value];
+      }
+    }
+  });
+  return actual;
+}
+
+// 处理毛利概算表
+function initEstimate(estimate, category) {
+  estimate.celldata.forEach(item => {
+    if (item.r == 15 && item.c == 2) {
+      // 金科制造中心-UF膜
+      item.v.v = category['GT-UF膜'];
+    } else if (item.r == 14 && item.c == 2) {
+      // 金科制造中心设备制造费
+      item.v.v = category['原平制造'];
+    } else if (item.r == 16 && item.c == 2) {
+      // 设备购置费
+      item.v.v =
+        category['其它膜'] +
+        category['水泵'] +
+        category['阀门'] +
+        category['加药系统'] +
+        category['过滤器'] +
+        category['空压机'] +
+        category['非标'] +
+        category['仪表'] +
+        category['电气自控'] +
+        category['材料'] +
+        category['运输'] +
+        category['其它'];
+    } else if (item.r == 18 && item.c == 2) {
+      // 数字双胞胎
+      item.v.v = category['双胞胎硬件'];
+    } else if (item.r == 19 && item.c == 2) {
+      // 安装
+      item.v.v = category['安装'];
+    } else if (item.r == 20 && item.c == 2) {
+      // 土建
+      item.v.v = category['土建'];
+    }
+  });
+  return estimate;
+}
+
+// 处理PSR表预算
+function initPSR(psr, category, projectName) {
+  psr.celldata.forEach(item => {
+    if (item.r == 0 && item.c == 1) {
+      item.v.v = projectName;
+    } else if (item.r == 38 && item.c == 2) {
+      item.v.v = category['GT-UF膜'];
+    } else if (item.r == 37 && item.c == 2) {
+      item.v.v = category['原平制造'];
+    } else if (item.r == 36 && item.c == 2) {
+      item.v.v =
+        category['其它膜'] +
+        category['水泵'] +
+        category['阀门'] +
+        category['加药系统'] +
+        category['过滤器'] +
+        category['空压机'] +
+        category['非标'] +
+        category['仪表'] +
+        category['电气自控'] +
+        category['材料'] +
+        category['运输'] +
+        category['其它'];
+    } else if (item.r == 39 && item.c == 2) {
+      item.v.v = category['双胞胎硬件'];
+    } else if (item.r == 40 && item.c == 2) {
+      item.v.v = category['安装'];
+    } else if (item.r == 41 && item.c == 2) {
+      item.v.v = category['土建'];
+    }
+  });
+  return psr;
+}
+
+export default uploadExcelByUrl;