Browse Source

比对word

Renxy 1 year ago
parent
commit
a006b30a8e

+ 4 - 1
package.json

@@ -48,9 +48,11 @@
     "bizcharts": "^3.5.5",
     "bizcharts-plugin-slider": "^2.1.1-beta.1",
     "braft-editor": "^2.3.9",
+    "buffer": "^6.0.3",
     "caniuse-lite": "^1.0.30001165",
     "classnames": "^2.2.6",
     "compression-webpack-plugin": "6.0.0",
+    "diff": "^5.1.0",
     "dingtalk-jsapi": "^2.15.4",
     "dva": "^2.4.1",
     "enquire-js": "^0.2.1",
@@ -67,6 +69,7 @@
     "lodash": "^4.17.11",
     "lodash-decorators": "^6.0.1",
     "luckyexcel": "^1.0.1",
+    "mammoth": "1.4.8",
     "memoize-one": "^5.0.0",
     "module": "^1.2.5",
     "moment": "^2.24.0",
@@ -75,7 +78,7 @@
     "nzh": "^1.0.4",
     "omit.js": "^1.0.0",
     "path-to-regexp": "^3.0.0",
-    "pdfjs-dist": "^3.3.122",
+    "pdfjs-dist": "3.3.122",
     "prop-types": "^15.6.2",
     "qrcode.react": "^3.1.0",
     "qs": "^6.6.0",

BIN
public/2023-6-16采购合同模板.docx


+ 8 - 4
src/app.js

@@ -1,4 +1,8 @@
 import fetch from 'dva/fetch';
+import * as buffer from 'buffer';
+if (typeof window.Buffer === 'undefined') {
+  window.Buffer = buffer.Buffer;
+}
 
 export const dva = {
   config: {
@@ -10,8 +14,8 @@ export const dva = {
 
 let authRoutes = {};
 window.test = () => {
-  console.log(1)
-}
+  console.log(1);
+};
 
 function ergodicRoutes(routes, authKey, authority) {
   routes.forEach(element => {
@@ -33,9 +37,9 @@ export function patchRoutes(routes) {
 }
 
 export function render(oldRender) {
-  authRoutes={
+  authRoutes = {
     '/form/advanced-form': { authority: ['admin', 'user'] },
-  }
+  };
   oldRender();
   // fetch('/api/auth_routes')
   //   .then(res => res.json())

+ 16 - 0
src/components/AttachmentTable/index.js

@@ -3,9 +3,11 @@ import { Divider, Table, Modal } from 'antd';
 import PreviewFile from '@/components/PreviewFile';
 import FileViewerModal from '@/components/FileViewer';
 import React, { useState, useMemo } from 'react';
+import PreviewWord from '../PreviewWord';
 
 function AttachmentTable(props) {
   const [excelFileVisible, setExcelFileVisible] = useState(false);
+  const [comparisonVisible, setComparisonVisible] = useState(false);
   const [exportData, setExportData] = useState({});
   const { loading, excelFileList, canDelete = true, dispatch, version } = props;
   const columns = [
@@ -34,9 +36,18 @@ function AttachmentTable(props) {
                 setExcelFileVisible(true);
                 setExportData(record);
               }}
+              style={{ marginRight: 10 }}
             >
               预览
             </a>
+            <a
+              onClick={() => {
+                setComparisonVisible(true);
+                setExportData(record);
+              }}
+            >
+              比对
+            </a>
           </>
         );
       },
@@ -85,6 +96,11 @@ function AttachmentTable(props) {
           setExcelFileVisible(false);
         }}
       />
+      <PreviewWord
+        open={comparisonVisible}
+        url={exportData?.url}
+        onCancel={() => setComparisonVisible(false)}
+      ></PreviewWord>
     </>
   );
 }

+ 128 - 0
src/components/PreviewWord/index.js

@@ -0,0 +1,128 @@
+import { useEffect, useState } from 'react';
+import s from './index.less';
+import { Modal } from 'antd';
+const jsDiff = require('diff');
+const mammoth = require('mammoth');
+const PreviewWord = ({ url, open, onCancel }) => {
+  const [diffArr, setDiffArr] = useState([]);
+  const [loading, setLoading] = useState(false);
+
+  // 读取input上传合同文件
+  const onChange = async id => {
+    const fileInput = document.getElementById(id);
+    const selectedFile = fileInput.files[0];
+    if (selectedFile) {
+      const readText = await readDocx(selectedFile);
+      // console.log(readText);
+      id == 'fileInput1' ? setValue1(readText) : setValue2(readText);
+    }
+  };
+  function readDocx(file) {
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+
+      reader.onload = function(event) {
+        const arrayBuffer = event.target.result;
+
+        mammoth
+          .extractRawText({ arrayBuffer: arrayBuffer })
+          .then(result => {
+            const text = result.value;
+            resolve(text);
+          })
+          .catch(err => {
+            reject(err);
+          });
+      };
+
+      reader.onerror = function(event) {
+        reject(new Error('文件读取失败'));
+      };
+
+      // 读取文件
+      reader.readAsArrayBuffer(file);
+    });
+  }
+
+  //读取当前url合同
+  const readUrlDocx = async url => {
+    const arrayBuffer = await fetch(url)
+      .then(res => {
+        if (!res.ok) {
+          throw new Error(`HTTP error! Status: ${res.status}`);
+        }
+        return res.arrayBuffer();
+      })
+      .catch(error => {
+        console.error('发生错误:', error);
+      });
+    return new Promise((resolve, reject) => {
+      mammoth
+        .extractRawText({ arrayBuffer: arrayBuffer })
+        .then(function(result) {
+          var text = result.value; // The raw text
+          const newText = text.replace(/\n+/g, '\n');
+          resolve(newText);
+        })
+        .catch(function(error) {
+          console.error(error);
+          reject(new Error('文件读取失败'));
+        });
+    });
+  };
+
+  const initData = async () => {
+    setLoading(true);
+    const text1 = await readUrlDocx('/2023-6-16采购合同模板.docx');
+    const text2 = await readUrlDocx(url);
+    if (!text1 || !text2) return;
+    const res = jsDiff['diffChars'](text1, text2);
+    console.log(res);
+    setLoading(false);
+    setDiffArr(res);
+  };
+
+  useEffect(() => {
+    if (!open || !url) return;
+    initData();
+  }, [open, url]);
+
+  const getCharDiff = () => {
+    const charColorMap = {
+      add: s.charAdd,
+      removed: s.charRemoved,
+    };
+    return (
+      <div>
+        {diffArr.map((item, index) => {
+          const { value, added, removed } = item;
+          const type = added ? 'add' : removed ? 'removed' : '';
+          return (
+            <span key={index} className={` ${charColorMap[type]} ${s.charPreWrap}`}>
+              {value}
+            </span>
+          );
+        })}
+      </div>
+    );
+  };
+  return (
+    <Modal
+      title="比对结果"
+      open={open}
+      loading={loading}
+      onCancel={onCancel}
+      width={1000}
+      footer={false}
+      bodyStyle={{ height: '80vh', overflowY: 'auto' }}
+    >
+      {getCharDiff()}
+    </Modal>
+    // <>
+    //   <input id="fileInput1" type="file" accept=".docx" onChange={() => onChange('fileInput1')} />
+    //   <input id="fileInput2" type="file" accept=".docx" onChange={() => onChange('fileInput2')} />
+    //   {getCharDiff()}
+    // </>
+  );
+};
+export default PreviewWord;

+ 16 - 0
src/components/PreviewWord/index.less

@@ -0,0 +1,16 @@
+.charAdd {
+  color: green;
+  background-color: rgb(236, 253, 240);
+}
+
+.charRemoved {
+  color: red;
+  background-color: rgb(251, 233, 235);
+}
+.charPreWrap {
+  white-space: pre-wrap;
+}
+// .result {
+//   //   font-size: 20px;
+//   padding-left: 10%;
+// }

+ 2 - 0
src/pages/List/List.js

@@ -13,6 +13,7 @@ import {
 import { getToken } from '@/utils/utils';
 import ClassifyModal from './ClassifyModal';
 import VersionModal from './VersionModal';
+import PreviewWord from '@/components/PreviewWord';
 
 let token = getToken();
 
@@ -286,6 +287,7 @@ function List(props) {
         onClose={() => setVisible(false)}
         handleChange={handleChange}
       />
+      <PreviewWord />
     </div>
   );
 }