Renxy 2 лет назад
Родитель
Сommit
627996291f
69 измененных файлов с 3953 добавлено и 944 удалено
  1. 1 0
      .gitignore
  2. 70 44
      .umirc.ts
  3. 0 0
      public/Luckysheet/luckysheet.umd.js
  4. 0 0
      public/Luckysheet/luckysheet.umd.js.map
  5. 122 0
      public/ZwCloud2DSDK/ZwCloud2D.d.ts
  6. 1 0
      public/ZwCloud2DSDK/ZwCloud2D.js
  7. 465 0
      public/ZwCloud2DSDK/ZwCloud2DPrivateAPI.js
  8. 660 0
      public/ZwCloud2DSDK/ZwCloud2DRestfulAPI.js
  9. 0 0
      public/ZwCloud2DSDK/ZwWasmJs.js
  10. BIN
      public/ZwCloud2DSDK/ZwWasmJs.wasm
  11. BIN
      public/ZwCloud2DSDK/adinit.dat
  12. BIN
      public/ZwCloud2DSDK/home_m.png
  13. BIN
      public/ZwCloud2DSDK/image1.png
  14. BIN
      public/ZwCloud2DSDK/image2.png
  15. 0 0
      public/ZwCloud2DSDK/readLMFData.js
  16. BIN
      public/ZwCloud2DSDK/text.png
  17. BIN
      public/ZwCloud2DSDK/textGlyph/SimSun-01.ttf
  18. 6 6
      public/luckysheet.html
  19. BIN
      src/assets/SideMenu/cadIcon.png
  20. BIN
      src/assets/UnityMenu/cad.png
  21. 32 25
      src/components/AuditForm/ComponentLibrary.js
  22. 124 15
      src/components/AuditForm/FormContent.js
  23. 147 0
      src/components/AuditForm/FormulaModal.js
  24. 99 4
      src/components/AuditForm/ItemAttribute.js
  25. 29 0
      src/components/AuditForm/constant.js
  26. 134 13
      src/components/AuditForm/index.js
  27. 52 0
      src/components/DDComponents/CodeFiled/index.js
  28. 2 2
      src/components/DDComponents/DDDateField/index.js
  29. 3 3
      src/components/DDComponents/DDSelectField/index.js
  30. 7 0
      src/components/DDComponents/DIYTable/index.css
  31. 210 0
      src/components/DDComponents/DIYTable/index.tsx
  32. 15 5
      src/components/DDComponents/DepartmentField/index.js
  33. 14 0
      src/components/DDComponents/FormulaField/index.js
  34. 2 1
      src/components/DDComponents/InnerContactField/index.js
  35. 2 1
      src/components/DDComponents/ManufacturerField/index.js
  36. 4 3
      src/components/DDComponents/NumberField/index.js
  37. 15 1
      src/components/DDComponents/index.js
  38. 4 2
      src/components/FileViewerNew/index.js
  39. 7 7
      src/components/PreviewFile/index.less
  40. 2 1
      src/components/UserDropdown/index.tsx
  41. 1 0
      src/models/depList.js
  42. 17 0
      src/pages/Cad/components/UploadModal.js
  43. 37 0
      src/pages/Cad/detail.js
  44. 148 0
      src/pages/Cad/index.js
  45. 1 1
      src/pages/ContractManager/component/AuditSteps.jsx
  46. 90 0
      src/pages/ContractManager/component/DraftModal.jsx
  47. 193 227
      src/pages/ContractManager/component/Modal.jsx
  48. 438 0
      src/pages/ContractManager/detail.js
  49. 64 46
      src/pages/ContractManager/index.jsx
  50. 3 4
      src/pages/FileManagement/index.js
  51. 6 6
      src/pages/Flow/Audit.js
  52. 38 10
      src/pages/Flow/OaAuditDetail.js
  53. 171 10
      src/pages/Flow/OaDetail.js
  54. 53 9
      src/pages/Flow/components/AuditDetailed.js
  55. 25 11
      src/pages/Flow/components/FormAndFilesNode.js
  56. 43 10
      src/pages/Flow/index.js
  57. 11 1
      src/pages/Home/index.js
  58. 2 1
      src/pages/ManufacturerMng/ManufacturerList.js
  59. 14 2
      src/pages/PSRManage/components/saveOtherModal.js
  60. 65 18
      src/pages/PSRManage/detail.js
  61. 2 1
      src/pages/Profile/apply.js
  62. 16 41
      src/pages/Profile/approve.js
  63. 2 1
      src/pages/Profile/approved.js
  64. 230 394
      src/pages/Profile/index.js
  65. 2 1
      src/pages/UserCenter/index.js
  66. 5 2
      src/services/approval.js
  67. 7 14
      src/services/boom.js
  68. 10 0
      src/services/cad.js
  69. 30 1
      src/services/contract.js

+ 1 - 0
.gitignore

@@ -11,3 +11,4 @@
 /dist
 /.mfsu
 .swc
+/.idea

+ 70 - 44
.umirc.ts

@@ -1,4 +1,5 @@
 import { defineConfig } from '@umijs/max';
+const publicPath = process.env.NODE_ENV == 'development' ? '/' : '/gt-dig/';
 
 export default defineConfig({
   hash: true,
@@ -13,28 +14,41 @@ export default defineConfig({
     locale: false,
   },
   title: '金科环境数字化管理平台',
-  publicPath: process.env.NODE_ENV == 'development' ? '/' : '/gt-dig/',
-  links: [
-    {
-      href: 'stylesheet',
-      rel: 'http://localhost:3000/plugins/css/pluginsCss.css',
-    },
-    { href: 'stylesheet', rel: 'http://localhost:3000/plugins/plugins.css' },
-    { href: 'stylesheet', rel: 'http://localhost:3000/css/luckysheet.css' },
-    {
-      href: 'stylesheet',
-      rel: 'http://localhost:3000/assets/iconfont/iconfont.css',
-    },
+  publicPath,
+  metas: [
+    // 配置html禁止缓存
+    { 'http-equiv': 'pragma', content: 'no-cache' },
+    { 'http-equiv': 'cache-control', content: 'no-cache' },
+    { 'http-equiv': 'expires', content: '0' },
+    { 'http-equiv': 'X-UA-Compatible', content: 'IE=EmulateIE9' },
   ],
-  scripts: [
-    { src: 'http://localhost:3000/plugins/js/plugin.js' },
-    { src: 'http://localhost:3000/luckysheet.umd.js' },
+  // links: [
+  //   {
+  //     href: 'stylesheet',
+  //     rel: 'http://localhost:3000/plugins/css/pluginsCss.css',
+  //   },
+  //   { href: 'stylesheet', rel: 'http://localhost:3000/plugins/plugins.css' },
+  //   { href: 'stylesheet', rel: 'http://localhost:3000/css/luckysheet.css' },
+  //   {
+  //     href: 'stylesheet',
+  //     rel: 'http://localhost:3000/assets/iconfont/iconfont.css',
+  //   },
+  // ],
+  // scripts: [
+  //   { src: '/ZwCloud2DSDK/ZwCloud2D.js' },
+  //   { src: '/ZwCloud2DSDK/ZwWasmJs.js' },
+  //   { src: '/ZwCloud2DSDK/ZwCloud2DAPI.js' },
+  // ],
+  headScripts: [
+    `${publicPath}ZwCloud2DSDK/ZwCloud2D.js`,
+    `${publicPath}ZwCloud2DSDK/ZwWasmJs.js`,
+    `${publicPath}ZwCloud2DSDK/ZwCloud2DPrivateAPI.js`,
   ],
   proxy: {
     '/api': {
-      // target: 'http://47.96.12.136:8888/',
-      target: 'http://47.96.12.136:8895/',
-      // target: 'http://120.55.44.4:8902/',
+      // target: 'http://192.168.20.232:1007/',
+      // target: 'http://47.96.12.136:8895/',
+      target: 'https://work.greentech.com.cn/',
       changeOrigin: true,
     },
   },
@@ -145,39 +159,39 @@ export default defineConfig({
     //     },
     //   ],
     // },
+    // {
+    //   name: '个人中心',
+    //   path: '/profile',
+    //   icon: 'https://gt-digitization.oss-cn-hangzhou.aliyuncs.com/doc/department/2023-04/profileIcon.png',
+    //   routes: [
+    //     {
+    //       name: '我的申请',
+    //       path: '/profile/apply',
+    //       component: './Profile/apply',
+    //     },
+    //     {
+    //       name: '我的审批',
+    //       path: '/profile/approve',
+    //       component: './Profile/approve',
+    //     },
+    //     {
+    //       name: '已审核',
+    //       path: '/profile/approved',
+    //       component: './Profile/approved',
+    //     },
+    //   ],
+    //   // component: './Profile/index',
+    //   // hideInMenu: true,
+    // },
     {
       name: '个人中心',
       path: '/profile',
+      component: './Profile/index',
       icon: 'https://gt-digitization.oss-cn-hangzhou.aliyuncs.com/doc/department/2023-04/profileIcon.png',
-      routes: [
-        {
-          name: '我的申请',
-          path: '/profile/apply',
-          component: './Profile/apply',
-        },
-        {
-          name: '我的审批',
-          path: '/profile/approve',
-          component: './Profile/approve',
-        },
-        {
-          name: '已审核',
-          path: '/profile/approved',
-          component: './Profile/approved',
-        },
-      ],
-      // component: './Profile/index',
-      // hideInMenu: true,
     },
-    // {
-    //   name: '个人中心',
-    //   path: '/profile',
-    //   component: './Profile/index',
-    //   hideInMenu: true,
-    // },
     {
       name: '审批详情',
-      path: '/profile/:id',
+      path: '/profile/detail',
       component: './Flow/OaAuditDetail',
       hideInMenu: true,
     },
@@ -199,6 +213,18 @@ export default defineConfig({
       component: './PSRManage/detail',
       hideInMenu: true,
     },
+    {
+      name: 'CAD实例',
+      path: '/cad',
+      component: './Cad',
+      icon: 'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-07-31/3f72fccf-4f9c-4891-a6ec-f04fe4b1d9a2.png',
+    },
+    {
+      name: 'CAD详情',
+      path: '/cad/detail',
+      component: './Cad/detail',
+      hideInMenu: true,
+    },
   ],
   npmClient: 'yarn',
 });

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
public/Luckysheet/luckysheet.umd.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
public/Luckysheet/luckysheet.umd.js.map


+ 122 - 0
public/ZwCloud2DSDK/ZwCloud2D.d.ts

@@ -0,0 +1,122 @@
+declare class Zw2DCloud {
+    /**
+     * Zw2DCloud 构造函数 传入一个div元素
+     * @param container 容器,一个div元素
+     */
+    constructor(container: HTMLDivElement)
+
+    /**
+     * 设置面板的属性:位置、大小等
+     * @param pageConfig 配置对象,详细信息请参考文档
+     */
+    ZwSetPageConfig(pageConfig: config): void
+
+    /**
+     * 进入图纸,可调用加载默认布局数据
+     * @param data lmf数据
+     */
+    ZwLoadDwgData(data: ArrayBuffer): void
+
+    /**
+     * 切换布局时,加载对应布局数据
+     * @param data lmf数据
+     */
+    ZwLoadLayoutData(data: ArrayBuffer): void
+
+    /**
+     * 设置布局信息
+     * @param info 布局信息的数组
+     */
+    ZwSetLayoutInfo(info: Array<{
+        handleId: number,
+        isDefault: 0 | 1,
+        layoutName: string,
+        order: number
+    }>): void
+
+    /**
+     * 传递图纸相关字体数据
+     * @param fontDatas 字体数据的数组
+     */
+    ZwSetFontDataList(fontDatas: Array<{
+        fontName: string,
+        fontData: ArrayBuffer
+    }>): void
+
+    /**
+     * 设置蒙版loading状态
+     * @param isLoading 布尔值,loading状态
+     */
+    ZwSetLoadingState(isLoading: boolean): void
+
+    /**
+     * 设置图纸内部图片数据
+     * @param imageDatas 图片数据的数组
+     */
+    ZwLoadImageData(imageDatas: Array<{
+        path: string,
+        data: ArrayBuffer
+    }>): void
+
+    /**
+     * 内部打印触发事件
+     * @param logInfo 打印事件抛出的信息
+     */
+    ZwEvtLogInfo(logInfo: {
+        type: 'Logger',
+        data: string
+    }): void
+
+    /**
+     * 切换布局触发的事件
+     * @param handleId 切换布局内部抛出的布局handleId
+     */
+    ZwEvtChangeLayout(handleId: number): void
+}
+
+type config = {
+    top?: number,
+    bottom?: number,
+    left?: number,
+    right?: number,
+
+    layerPanel?: {
+        WindowOrient?: "left"|"right"|"top"|"bottom",
+        WindowVisible?: "hide"|"show",
+        index?: number,
+        xval?: number,
+        yval?: number,
+        width?: number,
+        height?: number,
+        showPosition?: Array<"left" | "right" | "top" | "bottom">
+    },
+    xrefPanel?: {
+        WindowOrient?: "left" | "right" | "top" | "bottom",
+        WindowVisible?: "hide" | "show",
+        index?: number,
+        xval?: number,
+        yval?: number,
+        width?: number,
+        height?: number,
+        showPosition?: Array<"left" | "right" | "top" | "bottom">
+    },
+
+    commandPanel?: {
+        WindowOrient?: "left" | "right" | "top" | "bottom",
+        WindowVisible?: "hide" | "show",
+        index?: number,
+        xval?: number,
+        yval?: number,
+        width?: number,
+        height?: number,
+        showPosition?: Array<"left" | "right" | "top" | "bottom">
+    },
+    options?: {
+        usingWebGL?: boolean,
+        justShowTextBorder?: boolean,
+        zoomBreak?: boolean,
+        zoomNoHatch?: boolean,
+        cursorNotShow?: boolean,
+        cursorSize?: number,
+    }
+}

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
public/ZwCloud2DSDK/ZwCloud2D.js


+ 465 - 0
public/ZwCloud2DSDK/ZwCloud2DPrivateAPI.js

@@ -0,0 +1,465 @@
+let baseUrl = 'http://192.168.51.174:5199';
+let wsUrl = '';
+let dwgPath = '';
+let javaUrl = '';
+
+class Request {
+  constructor() {}
+
+  get(url, params, resType, type) {
+    return new Promise((res, rej) => {
+      let paramsArr = [];
+      for (let k in params) {
+        paramsArr.push(
+          encodeURIComponent(k) + '=' + encodeURIComponent(params[k]),
+        );
+      }
+      url = url + '?' + paramsArr.join('&');
+      let ajax = new XMLHttpRequest();
+      let checkUrl = type === 'java' ? javaUrl + url : baseUrl + url;
+      ajax.open('GET', checkUrl);
+      resType && (ajax.responseType = resType);
+      ajax.send();
+      ajax.onload = function () {
+        if (resType) res(ajax.response);
+        else {
+          let data = JSON.parse(ajax.response);
+          if (data.code === 0) {
+            res(data.data);
+          } else {
+            rej(data.msg);
+          }
+        }
+      };
+    });
+  }
+
+  post(url, params, resType, type) {
+    return new Promise((res, rej) => {
+      let ajax = new XMLHttpRequest();
+      let checkUrl = type === 'java' ? javaUrl + url : baseUrl + url;
+      ajax.open('POST', checkUrl);
+      resType && (ajax.responseType = resType);
+      if (!(params instanceof FormData)) {
+        ajax.setRequestHeader('content-type', 'application/json');
+      }
+      ajax.send(params);
+      ajax.onreadystatechange = function () {
+        if (ajax.readyState === 4) {
+          if (ajax.status === 200) {
+            res(ajax.response);
+          } else {
+            rej();
+          }
+        }
+      };
+    });
+  }
+
+  arrayBufferToBase64(buffer) {
+    let binary = '';
+    let bytes = new Uint8Array(buffer);
+    let len = bytes.byteLength;
+    for (let i = 0; i < len; i++) {
+      binary += String.fromCharCode(bytes[i]);
+    }
+    return btoa(binary);
+  }
+
+  fontDownload(fontName) {
+    return this.get('/sdk/font/download', { fontName }, 'blob');
+  }
+
+  transferDoc() {
+    return this.get('/sdk/transfer', {
+      projectId: 0,
+      dwgPath: dwgPath,
+      type: 1,
+    });
+  }
+
+  getDisplayData(handleId = 34) {
+    return this.get(
+      '/sdk/layout/lmf',
+      { projectId: 0, handleId, dwgPath: dwgPath },
+      'arraybuffer',
+    );
+  }
+
+  getXrefData(handleId, xrefIds) {
+    let params = { handleId: handleId, xrefIds: xrefIds, dwgPath: dwgPath };
+    params = JSON.stringify(params);
+    return this.post('/sdk/xref', params, 'arraybuffer');
+  }
+
+  getXrefRelation() {
+    return this.get('/sdk/xref/list', { dwgPath: dwgPath });
+  }
+
+  getXrefThumb(filePath) {
+    return this.get(
+      '/sdk/xref/thumb',
+      { filePath: filePath },
+      'arraybuffer',
+    ).then((res) => {
+      let url = this.arrayBufferToBase64(res);
+      return 'data:image/jpeg;base64,' + url;
+    });
+  }
+  getPlotData(params) {
+    let data = JSON.stringify(params);
+    return this.post('/sdk/print', data, 'arraybuffer');
+  }
+  getImageSrc(filePath) {
+    return this.get(
+      '/sdk/image/download',
+      { filePath: filePath },
+      'arraybuffer',
+    ).then((res) => {
+      let url = this.arrayBufferToBase64(res);
+      return 'data:image/jpeg;base64,' + url;
+    });
+  }
+  getImageData(filePath) {
+    return this.get(
+      '/sdk/image/download',
+      { filePath: filePath },
+      'arraybuffer',
+    );
+  }
+  getImageList() {
+    return this.get('/sdk/image/list');
+  }
+  getPermissionList() {
+    return this.get('/sdk/getStatus');
+  }
+  getRegenData(params) {
+    Object.assign(params, { dwgPath: dwgPath });
+    let data = JSON.stringify(params);
+    return this.post('/sdk/regen', data, 'arraybuffer');
+  }
+  getDwgFile() {
+    return this.get(
+      '/sdk/doc/download',
+      { dwgPath: dwgPath },
+      'arrayBuffer',
+      'java',
+    );
+  }
+  uploadFile(file) {
+    let formData = new FormData();
+    formData.append('file', file);
+    return this.post('/sdk/doc/upload', formData, 'json', 'java');
+  }
+}
+
+function resizeCheck() {
+  if (Date.now() - timer > 400) {
+    const windowInfo = {
+      width: window.innerWidth,
+      height: window.innerHeight,
+    };
+    console.log(windowInfo);
+    if (windowInfo.width <= 1190 || windowInfo.height <= 620) {
+      mainMobile.style.display = 'unset';
+      main.style.display = 'none';
+    } else {
+      mainMobile.style.display = 'none';
+      main.style.display = 'unset';
+    }
+    timer = Date.now();
+  }
+}
+
+ZwCloud2D.ZwDataProcessor.ZwSetConnectUrl = (url1, url2, url3) => {
+  javaUrl = url1;
+  baseUrl = url2;
+  wsUrl = url3;
+};
+
+ZwCloud2D.ZwDataProcessor.ZwSetLoadDwg = (path) => {
+  dwgPath = path;
+};
+
+ZwCloud2D.ZwDataProcessor.uploadDwg = (file) => {
+  let req = new Request();
+  return new Promise((resolve, reject) => {
+    req.uploadFile(file).then((res) => {
+      resolve(res);
+    });
+  });
+
+  // req.uploadFile(file).then(res => {
+  //     dwgPath = res.data.path;
+  //     ZwCloud2D.ZwDataProcessor.ZwLoad();
+  //     let main = document.getElementById('main');
+  //     main.style.display = "none"
+  //     let mainMobile = document.getElementById('main-mobile');
+  //     mainMobile.style.display = "none"
+  //     let showDwgBtn = document.getElementById('showDwgBtn');
+  //     let showFontBtn = document.getElementById('showFontBtn');
+  //     showDwgBtn.style.display = "unset"
+  //     showFontBtn.style.display = "unset"
+  // })
+};
+
+ZwCloud2D.ZwDataProcessor.uploadFont = (file) => {
+  let req = new Request();
+  let pArray = new Array();
+  for (let i = 0; i < file.length; i++) {
+    pArray.push(
+      new Promise((resolve, reject) => {
+        req.uploadFile(file[i]).then((res) => {
+          if (res.code === 200) {
+            resolve();
+          } else {
+            reject();
+          }
+        });
+      }),
+    );
+  }
+  Promise.all(pArray)
+    .then(() => {
+      alert('上传成功');
+    })
+    .catch(() => {
+      alert('上传失败');
+    });
+};
+
+ZwCloud2D.ZwDataProcessor.ZwLoad = () => {
+  let docId = new Date().getTime().toString();
+  let req = new Request();
+
+  // 切换布局时候触发回调
+  ZwCloud2D.ZwMessageCallback.ZwEvtChangeLayout = (layout) => {
+    req
+      .getDisplayData(layout.handleId)
+      .then((data) => {
+        let timestamp = new Date().getTime();
+        ZwCloud2D.ZwDataManager.ZwSetDwgData(layout.handleId, data, timestamp);
+      })
+      .catch((error) => {
+        console.error(error);
+      });
+  };
+  ZwCloud2D.ZwMessageCallback.ZwEvtLoadXrefData = (data) => {
+    req
+      .getXrefData(data.handleId, data.xrefIds)
+      .then((res) => {
+        ZwCloud2D.ZwDataManager.ZwSetXrefData(res);
+      })
+      .catch(() => {
+        ZwCloud2D.ZwDataManager.ZwSetXrefData();
+      });
+  };
+  ZwCloud2D.ZwMessageCallback.ZwEvtDrawEnd = () => {};
+
+  ZwCloud2D.ZwMessageCallback.ZwEvtGetRegenData = (data) => {
+    req
+      .getRegenData(data)
+      .then((res) => {
+        ZwCloud2D.ZwDataManager.ZwSetRegenData(res);
+      })
+      .catch(() => {
+        ZwCloud2D.ZwDataManager.ZwSetRegenData(null);
+      });
+  };
+  ZwCloud2D.ZwMessageCallback.ZwEvtLoadImageData = (data) => {
+    let pArr = new Array();
+    let imageMap = new Map();
+    data.forEach((imageUrl) => {
+      pArr.push(
+        new Promise((res, rej) => {
+          req
+            .getImageData(imageUrl)
+            .then((result) => {
+              imageMap.set(imageUrl, result);
+              res(true);
+            })
+            .catch((err) => {
+              res(true);
+            });
+        }),
+      );
+    });
+    Promise.all(pArr)
+      .then(() => {
+        ZwCloud2D.ZwDataManager.ZwSetImageData(imageMap);
+      })
+      .catch((error) => {
+        console.error(error);
+      });
+  };
+  ZwCloud2D.ZwMessageCallback.ZwEvtLoadImageList = () => {
+    req.getImageList().then((res) => {
+      res.forEach((image) => {
+        let path = image.completePath + image.name;
+        req.getImageSrc(path).then((imageData) => {
+          let item = {
+            name: image.name,
+            data: imageData,
+            completePath: image.completePath,
+          };
+          ZwCloud2D.ZwDataManager.ZwSetImageList(item);
+        });
+      });
+    });
+  };
+  ZwCloud2D.ZwMessageCallback.ZwEvtPlotDwg = (data) => {
+    let params = Object.assign(data.params, { dwgPath: dwgPath });
+    req
+      .getPlotData(params)
+      .then((res) => {
+        ZwCloud2D.ZwDataManager.ZwSetPlotData(data, res);
+        ZwCloud2D.ZwEditor.ZwSetLoadingState(false);
+      })
+      .catch((error) => {
+        console.error(error);
+      });
+  };
+  ZwCloud2D.ZwEditor.ZwSetUserOptions({ panel: { commentPanel: false } });
+  req
+    .getPermissionList()
+    .then((data) => {
+      ZwCloud2D.ZwDataManager.ZwSetSdkPermission(data);
+    })
+    .catch((error) => {
+      console.error(error);
+    });
+  if (!dwgPath) return;
+  req
+    .transferDoc()
+    .then((data) => {
+      // 显示当前布局的数据
+      let layouts = [];
+      data.layouts.forEach((layout) => {
+        let res = {
+          handleId: layout.handleId,
+          isDefault: layout.isDefault === 1 ? 'YES' : 'NO',
+          name: layout.layoutName,
+          tabOrder: layout.order,
+        };
+        layouts.push(res);
+      });
+      ZwCloud2D.ZwDataManager.ZwSetDwgInfo({
+        id: docId,
+        fonts: data.fontList,
+        layouts: layouts,
+        name: data.name,
+      }).then((res) => {
+        let pArr = [];
+        let fontArr = [];
+        res.missingFonts.forEach((fontName) => {
+          let arr = fontName.split('.');
+          let type = (arr[arr.length - 1] || '').toUpperCase();
+
+          pArr.push(
+            req.fontDownload(fontName).then(async (data) => {
+              if (data.type === 'application/octet-stream') {
+                let arraybuffer = await data.arrayBuffer();
+                fontArr.push({
+                  name: fontName,
+                  type: type,
+                  data: arraybuffer,
+                });
+              }
+            }),
+          );
+        });
+        Promise.all(pArr)
+          .then(() => {
+            ZwCloud2D.ZwDataManager.ZwSetFontDataList(fontArr).then(() => {
+              req
+                .getDisplayData(res.layout.handleId)
+                .then((lmfInfo) => {
+                  if (res.timestamp === '')
+                    res.timestamp = new Date().getTime();
+                  ZwCloud2D.ZwDataManager.ZwSetDwgData(
+                    res.layout.handleId,
+                    lmfInfo,
+                    res.timestamp,
+                  );
+                })
+                .catch((error) => {
+                  console.error(error);
+                });
+
+              req
+                .getXrefRelation()
+                .then((xrefRelations) => {
+                  let xrefPromises = [];
+                  let srcMap = new Map();
+                  xrefRelations.forEach((xrefRelation) => {
+                    if (xrefRelation.foundPath) {
+                      xrefPromises.push(
+                        new Promise((res, rej) => {
+                          req
+                            .getXrefThumb(xrefRelation.foundPath)
+                            .then((xrefThumb) => {
+                              srcMap.set(xrefRelation.foundPath, xrefThumb);
+                              res(true);
+                            });
+                        }),
+                      );
+                    }
+                  });
+                  Promise.all(xrefPromises)
+                    .then(() => {
+                      let params = {
+                        docName: data.name,
+                        xrefRelations: xrefRelations,
+                        srcMap: srcMap,
+                      };
+                      ZwCloud2D.ZwDataManager.ZwSetXrefList(params);
+                    })
+                    .catch(() => {
+                      let params = {
+                        docName: data.name,
+                        xrefRelations: xrefRelations,
+                        srcMap: srcMap,
+                      };
+                      ZwCloud2D.ZwDataManager.ZwSetXrefList(params);
+                    });
+                })
+                .catch((error) => {
+                  console.error(error);
+                });
+
+              if (wsUrl) {
+                let url =
+                  wsUrl +
+                  '/CadService?sub=' +
+                  Math.floor(Math.random() * 1000) +
+                  '&docId=' +
+                  docId +
+                  '&dwgPath=' +
+                  dwgPath;
+                ZwCloud2D.ZwDataManager.ZwEntryEdit(url);
+              }
+            });
+          })
+          .catch((error) => {
+            console.error(error);
+          });
+      });
+    })
+    .catch((error) => {
+      ZwCloud2D.ZwEditor.ZwSetLoadingState(false);
+
+      alert(error);
+      let main = document.getElementById('main');
+      main.style.display = 'unset';
+      let mainMobile = document.getElementById('main-mobile');
+      mainMobile.style.display = 'unset';
+      let showDwgBtn = document.getElementById('showDwgBtn');
+      let showFontBtn = document.getElementById('showFontBtn');
+      showDwgBtn.style.display = 'none';
+      showFontBtn.style.display = 'none';
+
+      resizeCheck();
+      window.addEventListener('resize', resizeCheck);
+      console.error(error);
+    });
+};

+ 660 - 0
public/ZwCloud2DSDK/ZwCloud2DRestfulAPI.js

@@ -0,0 +1,660 @@
+let baseUrl = 'http://192.168.51.174:9092'
+let userUrl = 'http://192.168.51.174:9091'
+let appKey = ''
+
+let docId = ''
+
+let fullVersionPermissions = {
+    'productName': 'ZW2D_CLOUD_FULL_2024',
+    'featureId': 167,
+    'projectId': 0,
+    'expiredTime': '2022-12-12T00:00:00',
+    'authClientNum': 10,
+    'forCloud2D': true,
+    'permissions': [
+        {
+            'description': 'DWG 100',
+            'name': 'DWG 100',
+            'permissionId': '100',
+            'type': 'SDK'
+        },
+        {
+            'description': 'DXF 101',
+            'name': 'DXF 101',
+            'permissionId': '101',
+            'type': 'SDK'
+        },
+        {
+            'description': '天正 102',
+            'name': '天正 102',
+            'permissionId': '102',
+            'type': 'SDK'
+        },
+        {
+            'description': '图纸预览图获取',
+            'name': '图纸预览图获取',
+            'permissionId': '201',
+            'type': 'SDK'
+        },
+        {
+            'description': '视口重生成',
+            'name': '视口重生成',
+            'permissionId': '202',
+            'type': 'SDK'
+        },
+        {
+            'description': '外部参照图片',
+            'name': '外部参照图片',
+            'permissionId': '203',
+            'type': 'SDK'
+        },
+        {
+            'description': 'DWG轻量数据生成',
+            'name': 'DWG轻量数据生成',
+            'permissionId': '204',
+            'type': 'SDK'
+        },
+        {
+            'description': '字体设置',
+            'name': '字体设置',
+            'permissionId': '205',
+            'type': 'SDK'
+        },
+        {
+            'description': '字体替换设置',
+            'name': '字体替换设置',
+            'permissionId': '206',
+            'type': 'SDK'
+        },
+        {
+            'description': '字体库',
+            'name': '字体库',
+            'permissionId': '207',
+            'type': 'SDK'
+        },
+        {
+            'description': '图纸二维线框显示',
+            'name': '图纸二维线框显示',
+            'permissionId': '300',
+            'type': 'SDK'
+        },
+        {
+            'description': '大图浏览(20M)',
+            'name': '大图浏览(20M)',
+            'permissionId': '301',
+            'type': 'SDK'
+        },
+        {
+            'description': '着色模式显示支持',
+            'name': '着色模式显示支持',
+            'permissionId': '302',
+            'type': 'SDK'
+        },
+        {
+            'description': '缩放',
+            'name': '缩放',
+            'permissionId': '303',
+            'type': 'SDK'
+        },
+        {
+            'description': '平移',
+            'name': '平移',
+            'permissionId': '304',
+            'type': 'SDK'
+        },
+        {
+            'description': '图片显示',
+            'name': '图片显示',
+            'permissionId': '305',
+            'type': 'SDK'
+        },
+        {
+            'description': '外部参照显示',
+            'name': '外部参照显示',
+            'permissionId': '306',
+            'type': 'SDK'
+        },
+        {
+            'description': '布局显示和切换',
+            'name': '布局显示和切换',
+            'permissionId': '307',
+            'type': 'SDK'
+        },
+        {
+            'description': '图层面板',
+            'name': '图层面板',
+            'permissionId': '308',
+            'type': 'SDK'
+        },
+        {
+            'description': '图层显示/隐藏',
+            'name': '图层显示/隐藏',
+            'permissionId': '309',
+            'type': 'SDK'
+        },
+        {
+            'description': '命令行窗口',
+            'name': '命令行窗口',
+            'permissionId': '310',
+            'type': 'SDK'
+        },
+        {
+            'description': '线宽显示',
+            'name': '线宽显示',
+            'permissionId': '311',
+            'type': 'SDK'
+        },
+        {
+            'description': '栅格显示',
+            'name': '栅格显示',
+            'permissionId': '312',
+            'type': 'SDK'
+        },
+        {
+            'description': '外部参照面板',
+            'name': '外部参照面板',
+            'permissionId': '313',
+            'type': 'SDK'
+        },
+        {
+            'description': '系统参数设置',
+            'name': '系统参数设置',
+            'permissionId': '314',
+            'type': 'SDK'
+        },
+        {
+            'description': '测量长度/面积/角度/坐标/弧长',
+            'name': '测量长度/面积/角度/坐标/弧长',
+            'permissionId': '400',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Text 单行文字',
+            'name': 'Text 单行文字',
+            'permissionId': '500',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Revcloud 云线',
+            'name': 'Revcloud 云线',
+            'permissionId': '501',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Leader 引线',
+            'name': 'Leader 引线',
+            'permissionId': '502',
+            'type': 'SDK'
+        },
+        {
+            'description': 'MLeader 多重引线',
+            'name': 'MLeader 多重引线',
+            'permissionId': '503',
+            'type': 'SDK'
+        },
+        {
+            'description': '图片(即图章功能)',
+            'name': '图片(即图章功能)',
+            'permissionId': '504',
+            'type': 'SDK'
+        },
+        {
+            'description': 'PLine 多段线',
+            'name': 'PLine 多段线',
+            'permissionId': '505',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Rectangle 矩形',
+            'name': 'Rectangle 矩形',
+            'permissionId': '506',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Circle 圆',
+            'name': 'Circle 圆',
+            'permissionId': '507',
+            'type': 'SDK'
+        },
+        {
+            'description': 'Arc 弧线',
+            'name': 'Arc 弧线',
+            'permissionId': '508',
+            'type': 'SDK'
+        },
+        {
+            'description': 'DWG导出',
+            'name': 'DWG导出',
+            'permissionId': '600',
+            'type': 'SDK'
+        },
+        {
+            'description': '图片输出',
+            'name': '图片输出',
+            'permissionId': '601',
+            'type': 'SDK'
+        },
+        {
+            'description': 'PDF输出',
+            'name': 'PDF输出',
+            'permissionId': '602',
+            'type': 'SDK'
+        },
+        {
+            'description': '添加预览水印',
+            'name': '添加预览水印',
+            'permissionId': '700',
+            'type': 'SDK'
+        },
+        {
+            'description': '书签、审图',
+            'name': '书签、审图',
+            'permissionId': '800',
+            'type': 'SDK'
+        },
+        {
+            'description': '批注面版',
+            'name': '批注面版',
+            'permissionId': '801',
+            'type': 'SDK'
+        },
+        {
+            'description': '书签定义和调用接口、布局信息和坐标转换接口、缩放比例和生成截图接口等',
+            'name': '书签定义和调用接口、布局信息和坐标转换接口、缩放比例和生成截图接口等',
+            'permissionId': '900',
+            'type': 'SDK'
+        },
+    ]
+}
+
+class Request {
+    constructor() {
+    }
+
+    getData(url, ticket, params, resType) {
+        return new Promise((res, rej) => {
+            let paramsArr = []
+            for (let k in params) {
+                paramsArr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
+            }
+            if (params) {
+                url = url + '?' + paramsArr.join('&')
+            }
+            let ajax = new XMLHttpRequest()
+            let ip = ticket ? userUrl : baseUrl
+            ajax.open('GET', ip + url)
+            resType && (ajax.responseType = resType)
+            ticket && Object.keys(ticket).forEach(key => {
+                ajax.setRequestHeader(key, ticket[key])
+            })
+            ajax.send()
+            ajax.onload = function () {
+                if (resType) res(ajax.response)
+                else {
+                    let data = JSON.parse(ajax.response)
+                    if (data.code === 0) {
+                        res(data.data)
+                    } else if (data.code === 2060) {
+                        rej(data.code)
+                    } else rej(data.msg)
+                }
+            }
+        })
+    }
+
+    postData(url, ticket, params, resType) {
+        return new Promise((res, rej) => {
+            let ajax = new XMLHttpRequest()
+            let ip = ticket ? userUrl : baseUrl
+            ajax.open('POST', ip + url)
+            resType && (ajax.responseType = resType)
+            ajax.setRequestHeader('content-type', 'application/json')
+            ticket && Object.keys(ticket).forEach(key => {
+                ajax.setRequestHeader(key, ticket[key])
+            })
+            ajax.send(params)
+            ajax.onreadystatechange = function () {
+                if (ajax.readyState === 4) {
+                    if (ajax.status === 200) {
+                        res(ajax.response)
+                    } else {
+                        rej()
+                    }
+                }
+            }
+        })
+    }
+
+    get(url, params, resType) {
+        if (appKey) {
+            let ticket = { 'x-ca-key': appKey }
+            return this.getData(url, ticket, params, resType)
+        } else {
+            return this.getData('/auth/js/ticket?url=' + url).then(res => {
+                let ticket = {
+                    'x-ca-key': res.appKey,
+                    'x-ca-nonce': res.nonce,
+                    'x-ca-date': res.timestamp,
+                    'x-ca-signature': res.signature,
+                }
+                return ticket
+            }).then(ticket => {
+                return this.getData(url, ticket, params, resType)
+            })
+        }
+    }
+
+    post(url, params, resType) {
+        if (appKey) {
+            let ticket = { 'x-ca-key': appKey }
+            return this.postData(url, ticket, params, resType)
+        } else {
+            return this.getData('/auth/js/ticket?url=' + url).then(res => {
+                let ticket = {
+                    'x-ca-key': res.appKey,
+                    'x-ca-nonce': res.nonce,
+                    'x-ca-date': res.timestamp,
+                    'x-ca-signature': res.signature,
+                }
+                return ticket
+            }).then(ticket => {
+                return this.postData(url, ticket, params, resType)
+            })
+        }
+
+    }
+
+    arrayBufferToBase64(buffer) {
+        let binary = '';
+        let bytes = new Uint8Array(buffer);
+        let len = bytes.byteLength;
+        for (let i = 0; i < len; i++) {
+            binary += String.fromCharCode(bytes[i]);
+        }
+        return btoa(binary);
+    }
+
+    fontDownload(fileId) {
+        return this.get('/api/js/v1/font/gzip', { fileId: fileId, projectId: 0 }, 'arraybuffer')
+    }
+
+    getTransferStatus(){
+        let params = { id: docId }
+        params = JSON.stringify(params)
+        return this.post('/api/js/v1/doc/transferStatus', params,'json')
+    }
+
+    transferDoc() {
+        return this.get('/api/js/v1/doc/details', { docId: docId })
+    }
+
+    getDisplayData(handleId = 34) {
+        return this.get('/api/js/v1/layout/lmf', { projectId: 0, handleId, docId: docId })
+    }
+
+    filePartDownload(lmfId) {
+        return this.get('/api/js/v1/file/partDownload', { fileId: lmfId }, 'arraybuffer')
+    }
+
+    getFileInfo(lmfId) {
+        return this.get('/api/js/v1/file/info', { id: lmfId })
+    }
+
+    getXrefRelation() {
+        return this.get('/api/js/v1/xref/info', { id: docId })
+    }
+
+    getXrefThumb(fileId) {
+        return this.get('/api/js/v1/file/partDownload', { fileId: fileId }, 'arraybuffer').then(res => {
+            let url = this.arrayBufferToBase64(res);
+            return 'data:image/jpeg;base64,' + url;
+        })
+    }
+
+    getXrefFile(handleId, xrefIds) {
+        let params = { docId: docId, handleId: handleId, xrefIds: xrefIds }
+        params = JSON.stringify(params)
+        return this.post('/api/js/v1/xref', params, 'json')
+    }
+
+    getImageInfo(filePath) {
+        let params = { docId: docId, path: filePath }
+        params = JSON.stringify(params)
+        return this.post('/api/js/v1/link', params, 'json')
+    }
+
+    getImageData(fileId) {
+        return this.get('/api/js/v1/file/partDownload', { fileId: fileId }, 'arraybuffer').then(res => {
+            let url = this.arrayBufferToBase64(res);
+            return 'data:image/jpeg;base64,' + url;
+        })
+    }
+
+    getPlotData(params) {
+        let data = JSON.stringify(params)
+        return this.post('/api/js/v1/doc/print', data, 'arraybuffer')
+    }
+
+    getBatchPlot(params) {
+        let data = JSON.stringify(params)
+        return this.post('/api/js/v1/doc/batchPrint', data, 'arraybuffer')
+    }
+
+    getRegenData(params) {
+        Object.assign(params, { docId: docId })
+        let data = JSON.stringify(params)
+        return this.post('/api/js/v1/layout/regen', data, 'arraybuffer')
+    }
+}
+
+ZwCloud2D.ZwDataProcessor.ZwSetConnectUrl = (url1, url2) => {
+    userUrl = url1
+    baseUrl = url2;
+}
+
+ZwCloud2D.ZwDataProcessor.ZwSetAppKey = (key) => {
+    appKey = key
+}
+
+ZwCloud2D.ZwDataProcessor.ZwSetLoadDwg = (path) => {
+    docId = path;
+}
+
+ZwCloud2D.ZwDataProcessor.ZwLoad = () => {
+
+    let req = new Request();
+
+    // 切换布局时候触发回调
+    ZwCloud2D.ZwMessageCallback.ZwEvtChangeLayout = layout => {
+        req.getDisplayData(layout.handleId).then(result => {
+            ZwCloud2D.ZwDataProcessor.ZwGetLmfData(result.lmfId).then(lmfInfo => {
+                if (lmfInfo) {
+                    function zcGetFileInfo() {
+                        req.getFileInfo(result.lmfId).then(fileInfo => {
+
+                            let curTimestamp = new Date(fileInfo.updateTime || fileInfo.createTime).getTime();
+
+                            if (lmfInfo.hasCache && curTimestamp.toString() === lmfInfo.timestamp) {
+                                ZwCloud2D.ZwDataManager.ZwSetDwgData(result.lmfId)
+                            } else {
+                                req.filePartDownload(result.lmfId).then(lmfInfo => {
+                                    ZwCloud2D.ZwDataManager.ZwSetDwgData(result.lmfId, lmfInfo, curTimestamp)
+                                })
+                            }
+                        }).catch((res) => {
+                            if (res === 2060) {
+                                this.timer = setTimeout(() => {
+                                    clearTimeout(this.timer)
+                                    zcGetFileInfo()
+                                }, 3000);
+                            } else {
+                                console.error(res)
+                            }
+                        })
+                    }
+                    zcGetFileInfo()
+                }
+            });
+        }).catch(error => {
+            console.error(error)
+        })
+    };
+
+    ZwCloud2D.ZwMessageCallback.ZwEvtLoadXrefData = data => {
+        req.getXrefFile(data.handleId, data.xrefIds).then(xrefFile => {
+            if (xrefFile.data.fileId) {
+                req.filePartDownload(xrefFile.data.fileId).then(fileData => {
+                    ZwCloud2D.ZwDataManager.ZwSetXrefData(fileData);
+                })
+            } else {
+                ZwCloud2D.ZwDataManager.ZwSetXrefData();
+            }
+        }).catch(() => {
+            ZwCloud2D.ZwDataManager.ZwSetXrefData();
+        })
+    };
+
+    ZwCloud2D.ZwMessageCallback.ZwEvtLoadImageData = data => {
+        let pArr = new Array();
+        let imageMap = new Map();
+        data.forEach((imageUrl) => {
+            pArr.push(new Promise((res, rej) => {
+                req.getImageInfo(imageUrl).then(info => {
+                    if (info.data.fileId) {
+                        req.getImageData(info.data.fileId).then(result => {
+                            imageMap.set(imageUrl, result);
+                            res(true)
+                        })
+                    } else {
+                        res(true)
+                    }
+                }).catch(err => {
+                    res(true);
+                });
+            }));
+        });
+        Promise.all(pArr).then(() => {
+            ZwCloud2D.ZwDataManager.ZwSetImageData(imageMap);
+        }).catch(error => {
+            console.error(error)
+        });
+    };
+    ZwCloud2D.ZwMessageCallback.ZwEvtPlotDwg = (data) => {
+        let params = Object.assign(data.params, { docId: docId })
+        if (params.isZwPlot) {
+            req.getBatchPlot(params).then(res => {
+                ZwCloud2D.ZwDataManager.ZwSetPlotData(data, res);
+                ZwCloud2D.ZwEditor.ZwSetLoadingState(false);
+            })
+        } else {
+            req.getPlotData(params).then(res => {
+                ZwCloud2D.ZwDataManager.ZwSetPlotData(data, res);
+                ZwCloud2D.ZwEditor.ZwSetLoadingState(false);
+            })
+        }
+    };
+    ZwCloud2D.ZwMessageCallback.ZwEvtGetRegenData = (data) => {
+        req.getRegenData(data).then(res => {
+            ZwCloud2D.ZwDataManager.ZwSetRegenData(res);
+        }).catch(() => {
+            ZwCloud2D.ZwDataManager.ZwSetRegenData(null);
+        });
+    };
+    let ZwMain=()=>{
+        req.transferDoc().then(data => {
+
+            ZwCloud2D.ZwDataManager.ZwSetSdkPermission(fullVersionPermissions);
+    
+            // 显示当前布局的数据
+            ZwCloud2D.ZwDataManager.ZwSetDwgInfo({ fonts: data.fonts, layouts: data.layouts, name: data.name }).then(res => {
+                let pArr = []
+                let fontArr = []
+    
+                res.missingFonts.forEach(font => {
+                    let arr = font.name.split('.');
+                    let type = (arr[arr.length - 1] || '').toUpperCase();
+    
+                    pArr.push(req.fontDownload(font.fileId).then(data => {
+                        if (data.byteLength > 0) {
+                            fontArr.push(
+                                {
+                                    name: font.name,
+                                    type: type,
+                                    data: data,
+                                }
+                            );
+                        }
+                    }));
+                });
+    
+                Promise.all(pArr).then(() => {
+                    ZwCloud2D.ZwDataManager.ZwSetFontDataList(fontArr).then(() => {
+    
+                        req.getDisplayData(res.layout.handleId).then(result => {
+    
+                            req.getXrefRelation().then(xrefRelations => {
+                                let xrefPromises = [];
+                                let srcMap = new Map();
+                                xrefRelations.forEach((xrefRelation) => {
+                                    if (xrefRelation.fileId) {
+                                        xrefPromises.push(new Promise((res, rej) => {
+                                            req.getXrefThumb(xrefRelation.fileId).then(xrefThumb => {
+                                                srcMap.set(xrefRelation.fileId, xrefThumb);
+                                                res(true);
+                                            });
+                                        }));
+                                    }
+                                });
+                                Promise.all(xrefPromises).then(() => {
+                                    let params = { docName: data.name, xrefRelations: xrefRelations, srcMap: srcMap };
+                                    ZwCloud2D.ZwDataManager.ZwSetXrefList(params);
+                                }).catch(() => {
+                                    let params = { docName: data.name, xrefRelations: xrefRelations, srcMap: srcMap };
+                                    ZwCloud2D.ZwDataManager.ZwSetXrefList(params);
+                                });
+                            });
+    
+                            req.getFileInfo(result.lmfId).then(lmfInfo => {
+                                let curTimestamp = new Date(lmfInfo.updateTime || lmfInfo.createTime).getTime();
+                                if (res.hasCache && res.timestamp === curTimestamp.toString()) {
+                                    ZwCloud2D.ZwDataManager.ZwSetDwgData(result.lmfId)
+                                } else {
+                                    req.filePartDownload(result.lmfId).then(lmfInfo => {
+                                        ZwCloud2D.ZwDataManager.ZwSetDwgData(result.lmfId, lmfInfo, curTimestamp)
+                                    })
+                                }
+                            }).catch(error => {
+                                console.error(error)
+                            })
+    
+                        }).catch(error => {
+                            console.error(error)
+                        })
+                    })
+                }).catch(error => {
+                    console.error(error)
+                })
+            });
+        }).catch(error => {
+            console.error(error)
+        });
+    }
+    let getTransferStatus=()=>{
+        req.getTransferStatus().then(fileInfo=>{
+            let status=fileInfo.data.status
+            if (status === 1) {
+                let timer = setTimeout(() => {
+                    clearTimeout(timer)
+                    getTransferStatus()
+                }, 3000);
+            } else if(status === 2) {
+                ZwMain()
+            }else if(status === 3){
+                console.error(fileInfo.failedReason)
+            }
+        }).catch(err=>{
+            console.error(err)
+        })
+    }
+    getTransferStatus()
+}

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
public/ZwCloud2DSDK/ZwWasmJs.js


BIN
public/ZwCloud2DSDK/ZwWasmJs.wasm


BIN
public/ZwCloud2DSDK/adinit.dat


BIN
public/ZwCloud2DSDK/home_m.png


BIN
public/ZwCloud2DSDK/image1.png


BIN
public/ZwCloud2DSDK/image2.png


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
public/ZwCloud2DSDK/readLMFData.js


BIN
public/ZwCloud2DSDK/text.png


BIN
public/ZwCloud2DSDK/textGlyph/SimSun-01.ttf


+ 6 - 6
public/luckysheet.html

@@ -8,12 +8,12 @@
   <title>Document</title>
 
   <!-- 线上发布使用路径 -->
-  <link rel="stylesheet" href="/bom/Luckysheet/plugins/css/pluginsCss.css" />
-  <link rel="stylesheet" href="/bom/Luckysheet/plugins/plugins.css" />
-  <link rel="stylesheet" href="/bom/Luckysheet/css/luckysheet.css" />
-  <link rel="stylesheet" href="/bom/Luckysheet/assets/iconfont/iconfont.css" />
-  <script src="/bom/Luckysheet/plugins/js/plugin.js"></script>
-  <script src="/bom/Luckysheet/luckysheet.umd.js"></script>
+  <link rel="stylesheet" href="/gt-dig/Luckysheet/plugins/css/pluginsCss.css" />
+  <link rel="stylesheet" href="/gt-dig/Luckysheet/plugins/plugins.css" />
+  <link rel="stylesheet" href="/gt-dig/Luckysheet/css/luckysheet.css" />
+  <link rel="stylesheet" href="/gt-dig/Luckysheet/assets/iconfont/iconfont.css" />
+  <script src="/gt-dig/Luckysheet/plugins/js/plugin.js"></script>
+  <script src="/gt-dig/Luckysheet/luckysheet.umd.js"></script>
 
   <!-- 本地开发使用路径 -->
   <link rel='stylesheet' href='http://localhost:3000/plugins/css/pluginsCss.css' />

BIN
src/assets/SideMenu/cadIcon.png


BIN
src/assets/UnityMenu/cad.png


+ 32 - 25
src/components/AuditForm/ComponentLibrary.js

@@ -3,16 +3,16 @@ import React, { useState } from 'react';
 import { COMPONENT_LIST } from './constant';
 
 function ComponentLibrary(props) {
-  const { visible, onCancel, onOk } = props;
-  const [currnetItem, setCurrentItem] = useState(null);
+  const { visible, onCancel, onOk, addToTable } = props;
+  const [currentItem, setCurrentItem] = useState(null);
 
   const handleOk = () => {
-    if (!currnetItem) {
+    if (!currentItem) {
       message.error('请选择控件');
       return;
     }
     setCurrentItem(null);
-    onOk?.(currnetItem);
+    onOk?.(currentItem);
   };
   const handleCancel = () => {
     setCurrentItem(null);
@@ -21,27 +21,34 @@ function ComponentLibrary(props) {
   return (
     <Modal open={visible} onCancel={handleCancel} onOk={handleOk}>
       <Row gutter={12} style={{ paddingTop: 20 }}>
-        {COMPONENT_LIST.map((item) => (
-          <Col span={8} key={item.componentName}>
-            <div
-              onClick={() => setCurrentItem(item)}
-              style={{
-                display: 'flex',
-                justifyContent: 'flex-start',
-                alignItems: 'center',
-                border:
-                  item == currnetItem ? '1px solid #1890FF' : '1px solid #aaa',
-                width: '100%',
-                padding: '4px 12px',
-                cursor: 'pointer',
-                margin: '10px 0',
-              }}
-            >
-              {item.icon}
-              <span style={{ marginLeft: 8 }}>{item.props.label}</span>
-            </div>
-          </Col>
-        ))}
+        {COMPONENT_LIST.map((item) => {
+          if (addToTable && item.props.label === '表格') {
+            return null;
+          }
+          return (
+            <Col span={8} key={item.componentName}>
+              <div
+                onClick={() => setCurrentItem(item)}
+                style={{
+                  display: 'flex',
+                  justifyContent: 'flex-start',
+                  alignItems: 'center',
+                  border:
+                    item === currentItem
+                      ? '1px solid #1890FF'
+                      : '1px solid #aaa',
+                  width: '100%',
+                  padding: '4px 12px',
+                  cursor: 'pointer',
+                  margin: '10px 0',
+                }}
+              >
+                {item.icon}
+                <span style={{ marginLeft: 8 }}>{item.props.label}</span>
+              </div>
+            </Col>
+          );
+        })}
       </Row>
     </Modal>
   );

+ 124 - 15
src/components/AuditForm/FormContent.js

@@ -1,13 +1,15 @@
-import { Form } from 'antd';
+import { Button, Form } from 'antd';
 import React, { useState, useMemo } from 'react';
 import {
   ArrowUpOutlined,
   ArrowDownOutlined,
   DeleteOutlined,
+  PlusOutlined,
 } from '@ant-design/icons';
+import position from '../Flow/node/fields/position';
 
 function FormContent(props) {
-  const { list, onChange, onSelect } = props;
+  const { list, onChange, onSelect, onTableColumnChange } = props;
   const [currentItem, setCurrentItem] = useState(null);
 
   const linkedList = useMemo(() => {
@@ -41,22 +43,24 @@ function FormContent(props) {
     _list[index] = temp;
     onChange(_list);
   };
-  const handleSelect = (index) => {
-    setCurrentItem(index);
-    onSelect(index);
+
+  const handleFormItemClick = (id) => {
+    setCurrentItem(id[0]);
+    onSelect(id);
   };
+
   return (
     <div style={{ width: 500, height: 636, overflow: 'auto' }}>
       {list.map((item, index) => {
         const btns = (
           <>
-            {index != 0 && (
+            {index !== 0 && (
               <ArrowUpOutlined
                 style={{ marginLeft: 5, cursor: 'pointer' }}
                 onClick={() => handleUp(index)}
               />
             )}
-            {index != list.length - 1 && (
+            {index !== list.length - 1 && (
               <ArrowDownOutlined
                 style={{ marginLeft: 5, cursor: 'pointer' }}
                 onClick={() => handleDown(index)}
@@ -68,14 +72,16 @@ function FormContent(props) {
             />
           </>
         );
+
         return (
           <FormItem
             key={item.props?.id}
             islinked={
-              linkedList?.findIndex((id) => id == item.props?.id) !== -1
+              linkedList?.findIndex((id) => id === item.props?.id) !== -1
             } //不等于-1表示是被单选框关联的组件需要置灰
-            active={index == currentItem}
-            onClick={() => handleSelect(index)}
+            active={item.props?.id === currentItem}
+            onClick={handleFormItemClick}
+            onTableColumnChange={onTableColumnChange}
             item={item}
             btns={btns}
           />
@@ -86,8 +92,46 @@ function FormContent(props) {
 }
 
 function FormItem(props) {
-  const { item, btns, active, onClick, islinked = false } = props;
+  const {
+    item,
+    btns,
+    active,
+    onClick,
+    onTableColumnChange,
+    islinked = false,
+  } = props;
   const { label, placeholder, required } = item.props;
+
+  // 子控件激活id
+  const [selectColumnID, setSelectColumnID] = useState('');
+
+  // 新增列时通过id定位
+  const addTableColumn = (event) => {
+    // 记录当前表格uuid
+    onTableColumnChange(item.props.id);
+  };
+
+  // 修改表格内部的控件顺序
+  const changeIndex = (index, operate) => {
+    let newCol = [...item.columns];
+    const prev = newCol[index - 1];
+    const next = newCol[index + 1];
+    switch (operate) {
+      case 'up':
+        newCol[index - 1] = newCol[index];
+        newCol[index] = prev;
+        break;
+      case 'down':
+        newCol[index + 1] = newCol[index];
+        newCol[index] = next;
+        break;
+      case 'delete':
+        newCol.splice(index, 1);
+        break;
+    }
+    onTableColumnChange(item.props.id, newCol);
+  };
+
   return (
     <div
       style={{
@@ -95,13 +139,24 @@ function FormItem(props) {
         marginBottom: 20,
         padding: '4px 12px',
         border: islinked ? '1px solid #bebcbc' : '1px solid #666',
-        borderLeft: active ? '10px solid #1890FF' : '1px solid #666',
+        borderLeft:
+          active && !item.isTable ? '10px solid #1890FF' : '1px solid #666',
+      }}
+      onClick={(e) => {
+        // 停止冒泡
+        e.stopPropagation();
+        if (item.isColumn === undefined) {
+          // 触发正常的事件
+          onClick([item.props.id]);
+        } else {
+          // 触发列中的click事件
+          onClick();
+        }
       }}
-      onClick={onClick}
     >
       <div
         style={{
-          fontSzie: 24,
+          fontSize: 16,
           color: '#000',
           fontWeight: 'bold',
           position: 'relative',
@@ -120,7 +175,61 @@ function FormItem(props) {
           {btns}
         </div>
       </div>
-      <div style={{ color: '#999', fontSize: 16 }}>{placeholder}</div>
+      {item.isTable ? (
+        <div style={{ padding: '10px 0 5px 0' }}>
+          {item.columns.map((column, index) => {
+            // column的按钮和外部的控件按钮不一样
+            const colBtns = (
+              <>
+                {index !== 0 && (
+                  <ArrowUpOutlined
+                    style={{ marginLeft: 5, cursor: 'pointer' }}
+                    onClick={() => {
+                      changeIndex(index, 'up');
+                    }}
+                  />
+                )}
+                {index !== item.columns.length - 1 && (
+                  <ArrowDownOutlined
+                    style={{ marginLeft: 5, cursor: 'pointer' }}
+                    onClick={() => {
+                      changeIndex(index, 'down');
+                    }}
+                  />
+                )}
+                <DeleteOutlined
+                  style={{ marginLeft: 5, cursor: 'pointer' }}
+                  onClick={() => {
+                    changeIndex(index, 'delete');
+                  }}
+                />
+              </>
+            );
+            return (
+              <FormItem
+                key={column.props?.id}
+                item={column}
+                active={active && column.props?.id === selectColumnID}
+                onClick={() => {
+                  setSelectColumnID(column.props.id);
+                  onClick([item.props.id, column.props.id]);
+                }}
+                btns={colBtns}
+              />
+            );
+          })}
+          <Button
+            type="dashed"
+            block
+            onClick={addTableColumn}
+            icon={<PlusOutlined />}
+          >
+            点击添加列
+          </Button>
+        </div>
+      ) : (
+        <div style={{ color: '#999', fontSize: 16 }}>{placeholder}</div>
+      )}
     </div>
   );
 }

+ 147 - 0
src/components/AuditForm/FormulaModal.js

@@ -0,0 +1,147 @@
+import { useEffect, useMemo, useState } from 'react';
+import { Divider, Input, Modal, Select, Table, message, Button } from 'antd';
+
+const { TextArea } = Input;
+
+export const FormulaType = {
+  Filed: 'filed',
+  Symbol: 'symbol',
+  Number: 'number',
+};
+
+const FormulaModal = (props) => {
+  const { item, numFiledList = [], visible, onCancel, onChange } = props;
+  const symbolList = ['+', '-', '*', '/', '(', ')'];
+  const numberList = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'];
+
+  const [formula, setFormula] = useState([]);
+
+  useEffect(() => {
+    if (!visible) setFormula([]);
+    if (item?.props) setFormula(item.props.formula || []);
+  }, [visible, item]);
+
+  const value = useMemo(() => {
+    const strList = formula.map((item) =>
+      item.type == FormulaType.Filed ? `【${item.label}】` : item.label,
+    );
+    return '计算公式=' + strList.join('');
+  }, [formula]);
+  console.log('-----------------', formula);
+
+  const isSameBeforItem = (type) => {
+    return formula.length > 0 && formula[formula.length - 1].type == type;
+  };
+
+  const handlerChange = (type, item) => {
+    let obj = {};
+    console.log(formula[formula.length - 1]);
+    switch (type) {
+      case FormulaType.Filed:
+        if (isSameBeforItem(FormulaType.Filed)) {
+          message.error('不能选择连续两个组件');
+        }
+        obj = {
+          type: FormulaType.Filed,
+          id: item.props.id,
+          label: item.props.label,
+        };
+        setFormula([...formula, obj]);
+        break;
+      case FormulaType.Symbol:
+        if (isSameBeforItem(FormulaType.Symbol)) {
+          message.error('不能选择连续两个符号');
+        }
+        obj = { type: FormulaType.Symbol, label: item };
+        setFormula([...formula, obj]);
+        break;
+      case FormulaType.Number:
+        //如果前一个选择的也是数字则合并数字 否则直接添加
+        if (isSameBeforItem(FormulaType.Number)) {
+          const len = formula.length - 1;
+          const label = formula[len].label + item;
+          obj = { type: FormulaType.Number, label };
+          const result = [...formula];
+          result[len] = obj;
+          setFormula(result);
+        } else {
+          obj = { type: FormulaType.Number, label: item };
+          setFormula([...formula, obj]);
+        }
+        break;
+    }
+  };
+
+  return (
+    <Modal
+      title="编辑计算公式"
+      open={visible}
+      onCancel={onCancel}
+      onOk={() => {
+        onChange?.({ ...item.props, formula, formulaLabel: value });
+      }}
+      width={1000}
+      pagination={false}
+    >
+      <Divider />
+
+      <Button
+        type="primary"
+        style={{ marginBottom: '20px' }}
+        onClick={() => setFormula([])}
+      >
+        清空
+      </Button>
+      <TextArea value={value} />
+      <div style={{ margin: '20px 20px 20px 0' }}>
+        计算对象:
+        {numFiledList.map((item, idx) => (
+          <span
+            style={{
+              padding: '6px 10px',
+              border: '1px solid #e5e5e5',
+              borderRadius: '2px',
+              marginRight: '10px',
+            }}
+            onClick={() => handlerChange(FormulaType.Filed, item)}
+          >
+            {item.props.label}
+          </span>
+        ))}
+      </div>
+      <div style={{ margin: '0 20px 20px 0' }}>
+        计算符号:
+        {symbolList.map((item, idx) => (
+          <span
+            style={{
+              padding: '6px 10px',
+              border: '1px solid #e5e5e5',
+              borderRadius: '2px',
+              marginRight: '10px',
+            }}
+            onClick={() => handlerChange(FormulaType.Symbol, item)}
+          >
+            {item}
+          </span>
+        ))}
+      </div>
+      <div style={{ margin: '0 20px 20px 0' }}>
+        数字键盘:
+        {numberList.map((item, idx) => (
+          <span
+            style={{
+              padding: '6px 10px',
+              border: '1px solid #e5e5e5',
+              borderRadius: '2px',
+              marginRight: '10px',
+            }}
+            onClick={() => handlerChange(FormulaType.Number, item)}
+          >
+            {item}
+          </span>
+        ))}
+      </div>
+    </Modal>
+  );
+};
+export default FormulaModal;

+ 99 - 4
src/components/AuditForm/ItemAttribute.js

@@ -1,9 +1,11 @@
 import { Form, Button, Switch, Input, Radio, Space, Row } from 'antd';
 import React, { useMemo, useState, useEffect } from 'react';
 import { DeleteOutlined } from '@ant-design/icons';
-function ItemAttribute(props) {
-  const { item, onChange, onRelClick } = props;
 
+function ItemAttribute(props) {
+  const { item, onChange, onRelClick, onFormulaClick } = props;
+  console.log(item);
+  if (!item) return null;
   const renderForm = () => {
     let FormContent;
     const formProps = {
@@ -57,13 +59,22 @@ function ItemAttribute(props) {
       case 'DDDateField':
         FormContent = <DDDateField {...formProps} />;
         break;
+      case 'DIYTable':
+        FormContent = <TableName {...formProps} />;
+        break;
+      case 'CodeField':
+        FormContent = <CodeField {...formProps} />;
+        break;
+      case 'FormulaField':
+        FormContent = (
+          <FormulaField {...formProps} onFormulaClick={onFormulaClick} />
+        );
+        break;
     }
 
     return FormContent;
   };
 
-  if (!item) return null;
-
   return (
     <div
       style={{
@@ -118,6 +129,7 @@ function InnerContactField(props) {
     </Form>
   );
 }
+
 function DepartmentField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -151,6 +163,7 @@ function DepartmentField(props) {
     </Form>
   );
 }
+
 function ProjectField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -176,6 +189,31 @@ function ProjectField(props) {
     </Form>
   );
 }
+function CodeField(props) {
+  const { item, btns, onFinish } = props;
+  const [form] = Form.useForm();
+  return (
+    <Form
+      form={form}
+      labelCol={{ span: 4 }}
+      wrapperCol={{ span: 20 }}
+      autoComplete="off"
+      initialValues={item.props}
+      onFinish={onFinish}
+    >
+      <Form.Item label="标题" name="label">
+        <Input />
+      </Form.Item>
+      <Form.Item label="提示文字" name="placeholder">
+        <Input />
+      </Form.Item>
+      <Form.Item label="必填" name="required" valuePropName="checked">
+        <Switch />
+      </Form.Item>
+      {btns}
+    </Form>
+  );
+}
 function ManufacturerField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -201,6 +239,7 @@ function ManufacturerField(props) {
     </Form>
   );
 }
+
 function TextField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -230,6 +269,7 @@ function TextField(props) {
     </Form>
   );
 }
+
 function DDAttachment(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -301,6 +341,7 @@ function DDDateField(props) {
     </Form>
   );
 }
+
 function TextareaField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -326,6 +367,7 @@ function TextareaField(props) {
     </Form>
   );
 }
+
 function DDSelectField(props) {
   const { item, btns, onFinish, onRelClick } = props;
   const [form] = Form.useForm();
@@ -368,6 +410,7 @@ function DDSelectField(props) {
     </Form>
   );
 }
+
 function DDMultiSelectField(props) {
   const { item, btns, onFinish } = props;
   const [form] = Form.useForm();
@@ -531,3 +574,55 @@ function NumberField(props) {
     </Form>
   );
 }
+
+function TableName(props) {
+  const { item, btns, onFinish } = props;
+  const [form] = Form.useForm();
+  return (
+    <Form
+      form={form}
+      labelCol={{ span: 4 }}
+      wrapperCol={{ span: 20 }}
+      autoComplete="off"
+      initialValues={item.props}
+      onFinish={onFinish}
+    >
+      <Form.Item label="表格名称" name="label">
+        <Input />
+      </Form.Item>
+      {btns}
+    </Form>
+  );
+}
+
+function FormulaField(props) {
+  const { item, btns, onFinish, onFormulaClick } = props;
+  const [form] = Form.useForm();
+  const value = useMemo(() => {
+    return item.props.formulaLabel;
+  }, [item.props]);
+  return (
+    <Form
+      form={form}
+      labelCol={{ span: 4 }}
+      wrapperCol={{ span: 20 }}
+      autoComplete="off"
+      initialValues={item.props}
+      onFinish={(values) => onFinish({ ...item.props, ...values })}
+    >
+      <Form.Item label="标题" name="label">
+        <Input />
+      </Form.Item>
+      <Form.Item label="提示文字" name="placeholder">
+        <Input />
+      </Form.Item>
+      <Form.Item label="计算公式">
+        <Input value={value} onClick={onFormulaClick} />
+      </Form.Item>
+      <Form.Item label="必填" name="required" valuePropName="checked">
+        <Switch />
+      </Form.Item>
+      {btns}
+    </Form>
+  );
+}

+ 29 - 0
src/components/AuditForm/constant.js

@@ -11,6 +11,9 @@ import {
   FontColorsOutlined,
   ProjectOutlined,
   SolutionOutlined,
+  NumberOutlined,
+  TableOutlined,
+  LaptopOutlined,
 } from '@ant-design/icons';
 
 export const COMPONENT_LIST = [
@@ -131,4 +134,30 @@ export const COMPONENT_LIST = [
       required: false,
     },
   },
+  {
+    componentName: 'CodeField',
+    icon: <NumberOutlined />,
+    props: {
+      label: '合同编号',
+      placeholder: '自动生成',
+      required: false,
+    },
+  },
+  {
+    componentName: 'DIYTable',
+    icon: <TableOutlined />,
+    props: {
+      label: '表格',
+      required: false,
+    },
+  },
+  {
+    componentName: 'FormulaField',
+    icon: <LaptopOutlined />,
+    props: {
+      label: '计算公式',
+      placeholder: '自动计算数值',
+      required: false,
+    },
+  },
 ];

+ 134 - 13
src/components/AuditForm/index.js

@@ -5,17 +5,49 @@ import ItemAttribute from './ItemAttribute';
 import { uuidv4 } from '@antv/xflow';
 import { Button } from 'antd';
 import RelModal from './RelModal';
+import FormulaModal from './FormulaModal';
 
 function AuditForm(props) {
   const { value, onChange } = props;
   const [formList, setFormList] = useState([]);
-  const [select, setSelect] = useState(-1);
+  const [select, setSelect] = useState('');
+  const [selectList, setSelectList] = useState([]);
   const [visible, setVisible] = useState(false);
+
   const [relVisible, setRelVisible] = useState(false); //关联选项弹窗
+  const [forVisible, setForVisible] = useState(false); //计算公式弹窗
+  const [addToTable, setAddToTable] = useState(false);
+  const [currentTableID, setCurrentTableID] = useState('');
+
+  console.log('-----------------', formList);
 
   const handleAddItem = (item) => {
-    const formItem = generateItem(item);
-    handleChangeList([...formList, formItem]);
+    if (addToTable) {
+      // 新增列处理
+      const column = generateItem(item);
+      // 找到对应的表格
+      const tableItem = formList.find(
+        (item) => item.props.id === currentTableID,
+      );
+      column.isColumn = true;
+      // 把新增的列加入到表格中
+      tableItem.columns.push(column);
+      // 把新增列的表格放回
+      const newFormList = [];
+      for (const item of formList) {
+        if (item.props.id !== currentTableID) {
+          newFormList.push(item);
+        } else {
+          newFormList.push(tableItem);
+        }
+      }
+      handleChangeList(newFormList);
+      setCurrentTableID('');
+    } else {
+      const formItem = generateItem(item);
+      handleChangeList([...formList, formItem]);
+    }
+    setAddToTable(false);
     setVisible(false);
   };
 
@@ -24,14 +56,40 @@ function AuditForm(props) {
       ...item,
       props: { ...item.props, id: `${item.componentName}_${uuidv4()}` },
     };
+    // 如果是表格的话
+    if (item.props.label === '表格') {
+      newItem.columns = [];
+      newItem.isTable = true;
+    }
     delete newItem.icon;
     return newItem;
   };
 
-  const onChangeAttribute = (newItem) => {
-    let oldValue = formList[select].props;
-    formList[select].props = { ...oldValue, ...newItem };
-    handleChangeList([...formList]);
+  const onChangeAttribute = (newItemProps) => {
+    let oldFormItem = findFormItem();
+    let newFormList = [];
+    // 是列
+    if (oldFormItem.isColumn) {
+      // 找到表格和col然后改掉属性
+      for (const item of formList) {
+        if (item.isTable) {
+          for (const column of item.columns) {
+            if (column.props.id === selectList[selectList.length - 1]) {
+              column.props = { ...column.props, ...newItemProps };
+            }
+          }
+        }
+        newFormList.push(item);
+      }
+    } else {
+      for (const item of formList) {
+        if (item.props.id === select) {
+          item.props = { ...item.props, ...newItemProps };
+        }
+        newFormList.push(item);
+      }
+    }
+    handleChangeList(newFormList);
   };
 
   const handleChangeList = (list) => {
@@ -39,6 +97,50 @@ function AuditForm(props) {
     onChange?.(list);
   };
 
+  // 表格列变化时(新增,调整顺序)
+  const handleTableColumnChange = (id, newCole = []) => {
+    if (newCole.length) {
+      // 调整col顺序
+      const tableItem = formList.find((item) => item.props.id === id);
+      tableItem.columns = newCole;
+      const newFormList = [];
+      for (const item of formList) {
+        if (item.props.id !== currentTableID) {
+          newFormList.push(item);
+        } else {
+          newFormList.push(tableItem);
+        }
+      }
+      handleChangeList(newFormList);
+    } else {
+      setCurrentTableID(id);
+      setAddToTable(true);
+    }
+  };
+
+  const handleFormContentSelect = (ids) => {
+    setSelectList(ids);
+    setSelect(ids[0]);
+  };
+
+  const findFormItem = () => {
+    let formItem = formList.find((item) => item.props.id === selectList[0]);
+
+    if (formItem?.isTable) {
+      // 如果是表格的话,还要寻找内部的被点击的col
+      if (selectList.length === 1) {
+        return formItem || null;
+      }
+      return (
+        formItem.columns.find(
+          (item) => item.props.id === selectList[selectList.length - 1],
+        ) || null
+      );
+    } else {
+      return formList.find((item) => item.props.id === select) || null;
+    }
+  };
+
   useEffect(() => {
     if (value instanceof Array) {
       setFormList([...value]);
@@ -59,24 +161,31 @@ function AuditForm(props) {
         }}
       >
         <FormContent
-          onSelect={setSelect}
+          onSelect={handleFormContentSelect}
           onChange={handleChangeList}
+          onTableColumnChange={handleTableColumnChange}
           list={formList}
         ></FormContent>
         <ItemAttribute
-          key={select}
-          item={formList[select]}
+          formList={formList}
+          key={selectList[selectList.length - 1]}
+          item={findFormItem()}
           onRelClick={() => setRelVisible(true)}
+          onFormulaClick={() => setForVisible(true)}
           onChange={onChangeAttribute}
         ></ItemAttribute>
       </div>
       <ComponentLibrary
+        addToTable={addToTable}
         onOk={handleAddItem}
-        visible={visible}
-        onCancel={() => setVisible(false)}
+        visible={visible || addToTable}
+        onCancel={() => {
+          setVisible(false);
+          setAddToTable(false);
+        }}
       />
       <RelModal
-        item={formList[select]}
+        item={formList.find((item) => item.props.id === select)}
         formList={formList}
         visible={relVisible}
         onCancel={() => setRelVisible(false)}
@@ -85,6 +194,18 @@ function AuditForm(props) {
           onChangeAttribute(value);
         }}
       />
+      <FormulaModal
+        item={formList.find((item) => item.props.id === select)}
+        numFiledList={formList.filter(
+          (item) => item.componentName == 'NumberField',
+        )}
+        visible={forVisible}
+        onCancel={() => setForVisible(false)}
+        onChange={(value) => {
+          setForVisible(false);
+          onChangeAttribute(value);
+        }}
+      />
     </div>
   );
 }

+ 52 - 0
src/components/DDComponents/CodeFiled/index.js

@@ -0,0 +1,52 @@
+import React, { useEffect, useState } from 'react';
+import { Input } from 'antd';
+import { useRequest, useModel } from '@umijs/max';
+import { queryContractCode } from '@/services/contract';
+
+function CodeField(props) {
+  const { depId, onChange } = props;
+  const { depList, run } = useModel('depList');
+  const [value, setValue] = useState('');
+
+  //计算合同编号接口
+  const { run: runCode } = useRequest((data) => queryContractCode(data), {
+    manual: true,
+    onSuccess: (data) => {
+      setValue(data?.code);
+      onChange?.(data?.code);
+    },
+  });
+  useEffect(() => {
+    run();
+  }, []);
+
+  useEffect(() => {
+    if (!depId) return;
+    const dep_code = getDepItemById(depId)?.Code;
+    const compony = depList.find((item) => item.Flag == 1);
+    let params = {
+      company_id: compony?.ID,
+      company_code: compony?.Code,
+      dep_code,
+    };
+    runCode(params);
+  }, [depId, depList]);
+
+  const getDepItemById = (id) => {
+    const fun = (list) => {
+      for (let i = 0; i < list.length; i++) {
+        let item = list[i];
+        if (item.ID == id) {
+          return item;
+        } else if (item.children?.length > 0) {
+          let res = fun(item.children);
+          if (res) return res;
+        }
+      }
+    };
+    return fun(depList);
+  };
+  return <Input value={value} placeholder="选择部门后自动生成" disabled />;
+}
+
+export default CodeField;

+ 2 - 2
src/components/DDComponents/DDDateField/index.js

@@ -2,10 +2,10 @@ import React from 'react';
 import { DatePicker } from 'antd';
 
 function DDDateField(props) {
-  const { format = "", disabled, onChange, placeholder } = props;
+  const { format = '', disabled, onChange, placeholder } = props;
 
   const handleChange = (date) => {
-    onChange?.(date.format('YYYY-MM-DD HH:mm:ss'));
+    onChange?.(date.format('YYYY-MM-DD HH:mm:ss'), props.id, props.label);
   };
   return (
     <DatePicker

+ 3 - 3
src/components/DDComponents/DDSelectField/index.js

@@ -10,11 +10,11 @@ function DDSelectField(props) {
     <Select
       style={{ width: '100%' }}
       disabled={disabled}
-      onChange={value => {
-        onChange(String(value));
+      onChange={(value) => {
+        onChange(String(value), props.id, props.label);
       }}
     >
-      {options?.map(cur => {
+      {options?.map((cur) => {
         return (
           <Option key={cur} value={cur}>
             {cur}

+ 7 - 0
src/components/DDComponents/DIYTable/index.css

@@ -0,0 +1,7 @@
+.hidden {
+  display: none;
+}
+
+.p-8{
+  padding: 10px !important;
+}

+ 210 - 0
src/components/DDComponents/DIYTable/index.tsx

@@ -0,0 +1,210 @@
+import React, { useEffect, useState } from 'react';
+// @ts-ignore
+import { Button, Input, Table } from 'antd';
+import type { ColumnsType } from 'antd/lib/table';
+import DDSelectField from '@/components/DDComponents/DDSelectField';
+import './index.css';
+import DDDateField from '@/components/DDComponents/DDDateField';
+import NumberField from '@/components/DDComponents/NumberField';
+import TextNote from '@/components/DDComponents/TextNote';
+import { PlusOutlined } from '@ant-design/icons';
+
+interface IProps {
+  table?: any; // 整个表格
+  columns?: Array<any>; // 当前列配置
+  onChange?: (e?: any, id?: string, label?: string) => void; // 表格修改后的值
+  displayOnly?: boolean; // 是否仅用于展示
+}
+
+type TableDataType = {
+  index: number;
+  id?: string;
+  col1?: any;
+  col2?: any;
+  col3?: any;
+  col4?: any;
+  col5?: any;
+};
+
+function DIYTable(props: IProps) {
+  const { table, columns, displayOnly, onChange } = props;
+  // table数据
+  const [tableData, setTableData] = useState<TableDataType[]>([{ index: 1 }]);
+  // table 列配置
+  const [tableColumnDef, setTableColumnDef] = useState<ColumnsType<any>>([
+    {
+      title: '序号',
+      dataIndex: 'index',
+      className: 'hidden',
+    },
+  ]);
+
+  // 表单填写时的表格生成
+  const handleGenerateTable = () => {
+    if (columns !== undefined && columns.length) {
+      for (let index = 0; index < columns.length; index++) {
+        let column = columns[index];
+        let columnID = column.props.id;
+        let columnLabel = column.props.label;
+        let colDef: any = {
+          dataIndex: 'col' + (index + 1),
+          title: columnLabel || column.name,
+          className: 'p-8',
+        };
+        switch (column.componentName) {
+          case 'DDSelectField':
+            colDef.render = (_: any, __: any, rowIndex: number) => {
+              let id =
+                rowIndex + ',' + index + ';' + columnID + '>' + table.props.id;
+              return (
+                <DDSelectField
+                  id={id}
+                  label={columnLabel + '>' + table.props.label}
+                  style={{ padding: '0', margin: '0' }}
+                  options={column.props.options}
+                  disabled={column.props.disabled}
+                  onChange={onChange}
+                />
+              );
+            };
+            break;
+          case 'DDDateField':
+            colDef.render = (_: any, __: any, rowIndex: number) => {
+              let id =
+                rowIndex + ',' + index + ';' + columnID + '>' + table.props.id;
+              return (
+                <DDDateField
+                  id={id}
+                  label={columnLabel + '>' + table.props.label}
+                  key={index + rowIndex + ''}
+                  style={{ padding: '0', margin: '0' }}
+                  placeholder={column.props.placeholder}
+                  format={column.props.format}
+                  disabled={column.props.disabled}
+                  onChange={onChange}
+                />
+              );
+            };
+            break;
+          case 'NumberField':
+            colDef.render = (_: any, __: any, rowIndex: number) => {
+              let id =
+                rowIndex + ',' + index + ';' + columnID + '>' + table.props.id;
+              return (
+                <NumberField
+                  id={id}
+                  label={columnLabel + '>' + table.props.label}
+                  size="small"
+                  width="50%"
+                  style={{ padding: '4px 11px' }}
+                  disabled={column.props.disabled}
+                  unit={column.props.unit}
+                  onChange={onChange}
+                />
+              );
+            };
+            break;
+          case 'TextField':
+            colDef.render = (_: any, __: any, rowIndex: number) => {
+              let id =
+                rowIndex + ',' + index + ';' + columnID + '>' + table.props.id;
+              return (
+                <Input
+                  disabled={column.props.disabled}
+                  placeholder={column.props.placeholder}
+                  onChange={(e) =>
+                    onChange?.(
+                      e.target.value,
+                      id,
+                      columnLabel + '>' + table.props.label,
+                    )
+                  }
+                />
+              );
+            };
+            break;
+          case 'TextNote':
+            colDef.title = '说明';
+            colDef.render = (_: any, __: any, rowIndex: number) => {
+              let id =
+                rowIndex + ',' + index + ';' + columnID + '>' + table.props.id;
+              return (
+                <TextNote
+                  id={id}
+                  style={{ padding: '0', margin: '0' }}
+                  value={column.props.placeholder}
+                />
+              );
+            };
+            break;
+        }
+        tableColumnDef.push(colDef);
+      }
+    }
+  };
+
+  // 当仅用作展示时
+  const handleDisplayOnly = () => {
+    const rows = columns;
+    const newTableData = [];
+    const newColumnDef: ColumnsType<any> = [];
+    if (rows && columns.length) {
+      for (let index = 0; index < rows.length; index++) {
+        // 把每一行的数据提出来到一个对象里
+        if (rows) {
+          const row = rows[index];
+
+          if (index === 0) {
+            // 列配置
+            row.forEach((col: any) => {
+              newColumnDef.push({ title: col.name, dataIndex: col.type });
+            });
+          }
+          let rowData: any = {};
+          row.forEach((col: any) => {
+            rowData[col.type] = col.value[0];
+            rowData.key = col.id + index;
+          });
+          newTableData.push(rowData);
+        }
+      }
+      setTableColumnDef(newColumnDef);
+      setTableData(newTableData);
+    }
+  };
+
+  const handleRowChange = () => {
+    setTableData([...tableData, { index: tableData.length }]);
+  };
+
+  useEffect(() => {
+    if (displayOnly) {
+      handleDisplayOnly();
+    } else {
+      handleGenerateTable();
+    }
+  }, []);
+
+  return (
+    <>
+      {table.name ? table.name : table.props.label}
+      <Table
+        style={displayOnly ? { margin: '10px 24px 10px 0' } : {}}
+        columns={tableColumnDef}
+        dataSource={tableData}
+        pagination={false}
+      />
+      <Button
+        type="dashed"
+        icon={<PlusOutlined />}
+        block
+        onClick={handleRowChange}
+        style={displayOnly ? { display: 'none' } : {}}
+      >
+        新增行
+      </Button>
+    </>
+  );
+}
+
+export default DIYTable;

+ 15 - 5
src/components/DDComponents/DepartmentField/index.js

@@ -1,10 +1,20 @@
-import { useModel } from '@umijs/max';
-import { TreeSelect } from 'antd';
+import { useRequest } from '@umijs/max';
+import { Select, TreeSelect } from 'antd';
 import { useEffect } from 'react';
+import { queryDepsV2 } from '@/services/approval';
 
 function DepartmentField(props) {
   const { value, onChange, disabled = false } = props;
-  const { depList, run, loading } = useModel('depList');
+  // const { depList, run, loading } = useModel('depList');
+  // 新建合同时,选择本部时,需要用另一个接口请求部门数据
+  const { data, run, loading } = useRequest(queryDepsV2, {
+    manual: true,
+    formatResult: (response) => {
+      return response.data?.map((item) => {
+        return { value: item.ID, label: item.Name };
+      });
+    },
+  });
 
   const onChangeValue = (newValue) => {
     onChange(String(newValue));
@@ -14,7 +24,7 @@ function DepartmentField(props) {
   }, []);
 
   return (
-    <TreeSelect
+    <Select
       showSearch
       // multiple
       allowClear
@@ -26,7 +36,7 @@ function DepartmentField(props) {
       loading={loading}
       style={{ width: '100%' }}
       placeholder="请选择部门"
-      treeData={depList}
+      options={data}
       onChange={onChangeValue}
       disabled={disabled}
     />

+ 14 - 0
src/components/DDComponents/FormulaField/index.js

@@ -0,0 +1,14 @@
+import React, { useEffect, useState } from 'react';
+import { Input } from 'antd';
+
+function FormulaField(props) {
+  const { evalStr, onChange } = props;
+  useEffect(() => {
+    const value = eval(evalStr);
+    onChange?.(value);
+  }, [evalStr]);
+
+  return <Input value={eval(evalStr)} />;
+}
+
+export default FormulaField;

+ 2 - 1
src/components/DDComponents/InnerContactField/index.js

@@ -6,8 +6,9 @@ const { Option } = Select;
 
 function InnerContactField(props) {
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   const { value, onChange, disabled = false } = props;
   const { userList, run, loading } = useModel('userList');
   useEffect(() => {

+ 2 - 1
src/components/DDComponents/ManufacturerField/index.js

@@ -7,8 +7,9 @@ const { Option } = Select;
 
 function ManufacturerField(props) {
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   const { value, disabled = false, onChange } = props;
   //供应商列表
   const {

+ 4 - 3
src/components/DDComponents/NumberField/index.js

@@ -2,15 +2,16 @@ import React from 'react';
 import { InputNumber } from 'antd';
 
 function NumberField(props) {
-  const { onChange, disabled, unit } = props;
+  const { onChange, disabled, unit, size, width } = props;
 
   return (
     <InputNumber
-      style={{ width: '100%' }}
+      size={size}
+      style={{ width: '100%', padding: size === 'small' ? '4px' : '0' }}
       disabled={disabled}
       formatter={(value) => `${value}${unit || ''}`}
       onChange={(e) => {
-        onChange?.(e ? String(e) : 0);
+        onChange?.(e ? String(e) : 0, props.id, props.label);
       }}
     />
   );

+ 15 - 1
src/components/DDComponents/index.js

@@ -13,9 +13,12 @@ import DDDateField from './DDDateField';
 import DDDateRangeField from './DDDateRangeField';
 import DDAttachment from './DDAttachment';
 import TextNote from './TextNote';
+import CodeField from './CodeFiled';
+import DIYTable from './DIYTable';
+import FormulaField from './FormulaField';
 
 export default function DDComponents(props) {
-  const { item, onChange } = props;
+  const { depId = '', evalStr = '', item, onChange } = props;
   const { placeholder, options, format, unit, disabled, notUpper } = item.props;
   let component = null;
   switch (item.componentName) {
@@ -111,6 +114,17 @@ export default function DDComponents(props) {
     case 'ManufacturerField':
       component = <ManufacturerField onChange={onChange} />;
       break;
+    case 'DIYTable':
+      component = (
+        <DIYTable table={item} columns={item.columns} onChange={onChange} />
+      );
+      break;
+    case 'CodeField': //合同编号控件
+      component = <CodeField depId={depId} onChange={onChange} />;
+      break;
+    case 'FormulaField': //计算控件
+      component = <FormulaField evalStr={evalStr} onChange={onChange} />;
+      break;
     case 'RelateField': //关联审批单
       component = '关联审批单控件未渲染!';
       break;

+ 4 - 2
src/components/FileViewerNew/index.js

@@ -7,6 +7,7 @@ import { Modal, Table } from 'antd';
 
 const FileViewerModal = ({ data, visible, onCancel, downloadFile }) => {
   const [img, setImg] = useState();
+  const [open, setOpen] = useState(false);
   useEffect(() => {
     if (!visible) setImg(null);
   }, [visible]);
@@ -66,7 +67,7 @@ const FileViewerModal = ({ data, visible, onCancel, downloadFile }) => {
       </>
     );
   };
-
+  ////open && renderContent(data) 解决渲染的预览pdf宽高为空问题
   return (
     <Modal
       destroyOnClose
@@ -76,8 +77,9 @@ const FileViewerModal = ({ data, visible, onCancel, downloadFile }) => {
       footer={null}
       onCancel={onCancel}
       bodyStyle={{ height: '680px', overflowY: 'hidden' }}
+      afterOpenChange={setOpen} //modal完全渲染完成之后的回调
     >
-      {Array.isArray(data) ? renderListContent() : renderContent(data)}
+      {Array.isArray(data) ? renderListContent() : open && renderContent(data)}
     </Modal>
   );
 };

+ 7 - 7
src/components/PreviewFile/index.less

@@ -1,8 +1,8 @@
-  #zmageControlZoom {
-    display: none;
-  }
+#zmageControlZoom {
+  display: none;
+}
 
-  #zmageControl {
-    transform: scale(0.4);
-    transform-origin: top right;
-  }
+#zmageControl {
+  transform: scale(0.3);
+  transform-origin: top right;
+}

+ 2 - 1
src/components/UserDropdown/index.tsx

@@ -23,8 +23,9 @@ const RenderDropDown = (menu: any) => {
 
 export default function UserDropdown(props: any) {
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   return (
     <div className={styles.root}>
       <Dropdown placement="top" dropdownRender={(menu) => RenderDropDown(menu)}>

+ 1 - 0
src/models/depList.js

@@ -19,6 +19,7 @@ const depList = () => {
       return getDepUserTree(item);
     });
   }
+  console.log(depList);
   return { depUserTree, depList, loading, run };
 };
 function getDepUserTree(data) {

+ 17 - 0
src/pages/Cad/components/UploadModal.js

@@ -0,0 +1,17 @@
+import { Checkbox, Modal, message, Space, Divider } from 'antd';
+import { useEffect, useMemo, useRef, useState } from 'react';
+import dayjs from 'dayjs';
+
+const UploadModal = ({ open, onCancel, onOk }) => {
+  useEffect(() => {}, [open]);
+  return (
+    <Modal
+      title="上传"
+      open={open}
+      onCancel={onCancel}
+      onOk={() => onOk(values)}
+      destroyOnClose
+    ></Modal>
+  );
+};
+export default UploadModal;

+ 37 - 0
src/pages/Cad/detail.js

@@ -0,0 +1,37 @@
+import { useRef, useEffect } from 'react';
+import PageContent from '@/components/PageContent';
+import { useLocation, useNavigate } from '@umijs/max';
+
+const CadDeTail = () => {
+  const cadRef = useRef();
+  const location = useLocation();
+  const {
+    state: { path },
+  } = location;
+
+  useEffect(() => {
+    console.log(window);
+    const content = document.getElementById('container');
+    window.ZwCloud2D.ZwEditor.ZwInit(content);
+
+    ZwCloud2D.ZwDataProcessor.ZwSetConnectUrl(
+      'http://222.130.26.205:9080',
+      'http://222.130.26.205:5121',
+      'ws://222.130.26.205:5121',
+    );
+    ZwCloud2D.ZwDataProcessor.ZwSetLoadDwg(path);
+    window.ZwCloud2D.ZwDataProcessor.ZwLoad();
+  }, []);
+  return (
+    <PageContent>
+      <div>CAD在线审批</div>
+      <div
+        id="container"
+        style={{ width: '100%', height: '80vh' }}
+        ref={cadRef}
+      />
+    </PageContent>
+  );
+};
+
+export default CadDeTail;

+ 148 - 0
src/pages/Cad/index.js

@@ -0,0 +1,148 @@
+import { useRef, useEffect, useState } from 'react';
+import PageContent from '@/components/PageContent';
+import { queryCadList, queryCreateCad } from '@/services/cad';
+import { useRequest, useNavigate } from '@umijs/max';
+import { Table, Button, message, Space } from 'antd';
+
+const CadDemo = () => {
+  let navigate = useNavigate();
+  const columns = [
+    {
+      title: '名称',
+      dataIndex: 'name',
+      key: 'name',
+      align: 'center',
+      width: 160,
+    },
+    {
+      title: '创建人',
+      dataIndex: 'created_by',
+      key: 'created_by',
+      align: 'center',
+      width: 120,
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'created_on',
+      key: 'created_on',
+      align: 'center',
+      width: 100,
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      key: 'status',
+      align: 'center',
+      width: 100,
+      render: (status) => {
+        let str = '';
+        let color = 'black';
+        switch (status) {
+          case 1:
+            str = '待审核';
+            color = 'blue';
+            break;
+          case 2:
+            str = '审核通过';
+            color = 'red';
+            break;
+          case 3:
+            str = '审核拒绝';
+            color = 'green';
+            break;
+        }
+        return <div style={{ color }}>{str}</div>;
+      },
+    },
+    {
+      title: '操作',
+      align: 'center',
+      width: '10%',
+      render: (record) => (
+        <Space>
+          <a
+            onClick={() =>
+              navigate('/cad/detail', {
+                state: {
+                  path: record.path,
+                },
+              })
+            }
+          >
+            详情
+          </a>
+          <a onClick={() => {}}>提审</a>
+        </Space>
+      ),
+    },
+  ];
+  const [uploading, setUpLoading] = useState(false);
+
+  //请求列表
+  const { data, run, loading } = useRequest(queryCadList);
+
+  //上传
+  const { run: runCreate } = useRequest((data) => queryCreateCad(data), {
+    manual: true,
+    onSuccess: () => {
+      run();
+      message.success('上传成功');
+      setUpLoading(false);
+    },
+  });
+
+  useEffect(() => {
+    ZwCloud2D.ZwDataProcessor.ZwSetConnectUrl(
+      'http://222.130.26.205:9080',
+      'http://222.130.26.205:5121',
+      'ws://222.130.26.205:5121',
+    );
+  }, []);
+
+  function uploadDwg(event) {
+    const selectedFile = event.target.files[0];
+    if (selectedFile) {
+      // ZwCloud2D.ZwEditor.ZwSetLoadingState(true);
+      setUpLoading(true);
+      ZwCloud2D.ZwDataProcessor.uploadDwg(selectedFile).then((res) => {
+        if (res.code == 200) {
+          runCreate({ name: res.data.name, path: res.data.path });
+        }
+        setUpLoading(false);
+      });
+    }
+  }
+  function dwgUpload() {
+    let uploadDwg = document.getElementById('uploadDwg');
+    uploadDwg.click();
+  }
+
+  return (
+    <PageContent>
+      <Button type="primary" onClick={dwgUpload}>
+        上传
+      </Button>
+      <Table
+        loading={loading}
+        columns={columns}
+        dataSource={data?.list}
+        indentSize={70}
+        // pagination={{
+        //   ...pagination,
+        //   showSizeChanger: false,
+        //   onChange: onPageChange,
+        // }}
+      />
+      {/* <div id="container"></div> */}
+      <input
+        style={{ display: 'none' }}
+        id="uploadDwg"
+        type="file"
+        onChange={uploadDwg}
+        accept=".dwg, .dxf"
+      />
+    </PageContent>
+  );
+};
+
+export default CadDemo;

+ 1 - 1
src/pages/ContractManager/component/AuditSteps.jsx

@@ -1,4 +1,4 @@
-import { Steps } from 'antd';
+import { Steps, Tooltip } from 'antd';
 const AuditSteps = (props) => {
   // const data =
   //   '[{"id":13,"desc":"","auditor":7,"AuditorUser":{"UserName":"admin","CName":"管理员","Title":"","Mobile":"13426370450","Email":"123123@qq.com","Status":1,"IsSuper":true,"DepId":"undefined","Dep":null,"Password":"4297f44b13955235245b2497399d7a93","QyWxUserId":"HanTangHeYing","DingUserId":"","Role":null,"RoleNames":"","ID":7,"CreatedBy":0,"CreatedOn":"2019-10-04T16:48:04+08:00","UpdatedBy":0,"UpdatedOn":"2022-06-17T14:23:15+08:00","DeletedBy":0,"DeletedOn":null,"DeletedFlag":0,"DefaultProject":"","ForbiddenModule":0,"IsDepLeader":0,"UserType":0,"Permission":null,"Permissions":null,"is_leader":0,"is_accountant":0,"is_opt_mgr":0,"is_wty_mgr":0},"seq":1,"oa_id":7,"seq_name":"审批1","audit_time":"1970-01-01T08:00:00+08:00"},{"id":14,"desc":"","auditor":7,"AuditorUser":{"UserName":"admin","CName":"管理员","Title":"","Mobile":"13426370450","Email":"123123@qq.com","Status":1,"IsSuper":true,"DepId":"undefined","Dep":null,"Password":"4297f44b13955235245b2497399d7a93","QyWxUserId":"HanTangHeYing","DingUserId":"","Role":null,"RoleNames":"","ID":7,"CreatedBy":0,"CreatedOn":"2019-10-04T16:48:04+08:00","UpdatedBy":0,"UpdatedOn":"2022-06-17T14:23:15+08:00","DeletedBy":0,"DeletedOn":null,"DeletedFlag":0,"DefaultProject":"","ForbiddenModule":0,"IsDepLeader":0,"UserType":0,"Permission":null,"Permissions":null,"is_leader":0,"is_accountant":0,"is_opt_mgr":0,"is_wty_mgr":0},"seq":2,"oa_id":7,"seq_name":"审批2","audit_time":"1970-01-01T08:00:00+08:00"}]';

+ 90 - 0
src/pages/ContractManager/component/DraftModal.jsx

@@ -0,0 +1,90 @@
+import { Modal, Table, Space, Divider, message } from 'antd';
+import { useRequest, useModel } from '@umijs/max';
+import { queryContractDraft } from '@/services/contract';
+import { queryDelDraft } from '../../../services/contract';
+import { useEffect } from 'react';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+
+const DraftModal = ({ open, onCancel, onOk }) => {
+  const [modal, contextHolder] = Modal.useModal();
+  const columns = [
+    {
+      title: '合同名称',
+      dataIndex: 'name',
+      key: 'name',
+      width: 100,
+    },
+    {
+      title: '操作',
+      width: '40%',
+      align: 'center',
+      render: (record) => {
+        return (
+          <Space>
+            <a onClick={() => handlerOk(record)}>打开</a>
+            <a onClick={() => handleDel(record.id)}>删除</a>
+          </Space>
+        );
+      },
+    },
+  ];
+
+  const handleDel = (id) => {
+    modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title: '提示:',
+      content: <div>确定删除草稿!</div>,
+      onOk: () => runDel({ id }),
+    });
+  };
+
+  useEffect(() => {
+    if (open) runList();
+  }, [open]);
+
+  const {
+    data,
+    loading,
+    run: runList,
+  } = useRequest(queryContractDraft, {
+    formatResult: (res) => {
+      if (res?.data) {
+        return res.data?.list;
+      }
+    },
+  });
+
+  const { run: runDel } = useRequest(queryDelDraft, {
+    manual: true,
+    onSuccess: (res) => {
+      message.success('删除成功');
+      runList();
+    },
+  });
+
+  const handlerOk = (record) => {
+    const data = JSON.parse(record.content);
+    onOk(data);
+  };
+
+  return (
+    <Modal
+      title="草稿箱"
+      open={open}
+      footer={null}
+      onCancel={onCancel}
+      onOk={onOk}
+      width={700}
+    >
+      <Table
+        dataSource={data}
+        columns={columns}
+        loading={loading}
+        pagination={false}
+      />
+      {contextHolder}
+    </Modal>
+  );
+};
+
+export default DraftModal;

+ 193 - 227
src/pages/ContractManager/component/Modal.jsx

@@ -26,6 +26,7 @@ import {
   queryOAReCall,
   querySupplierList,
 } from '@/services/contract';
+import { queryDepsV2 } from '@/services/approval';
 import { useModel, useRequest } from '@umijs/max';
 import { CloudUploadOutlined } from '@ant-design/icons';
 import styles from '../index.less';
@@ -37,7 +38,7 @@ export const Type = {
   add: 0, //新增
   detail: 1, //详情
   cancel: 2, //作废
-  check: 3, //审核
+  save: 3, //保存草稿
 };
 
 export const StatusText = [
@@ -62,9 +63,8 @@ export const Status = {
 
 const ContractModal = (props) => {
   const [form] = Form.useForm();
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const { userList, run: userListRun } = useModel('userList');
   const { depList, run: depListRun } = useModel('depList');
   const [auditList, setAuditList] = useState([]);
@@ -93,8 +93,6 @@ const ContractModal = (props) => {
       ID: '行政部',
     },
   ];
-
-  const [isPass, setIsPass] = useState(1);
   const [companyDepList, setCompanyDepList] = useState(depList || []);
   const [archivesDepList, setArchivesDepList] = useState(archivesOptions);
   const [dealDisable, setDealDisable] = useState(false);
@@ -106,6 +104,9 @@ const ContractModal = (props) => {
   const project_name = Form.useWatch('project_name', form);
   const archives_dep = Form.useWatch('archives_dep', form);
 
+  // 当为审核拒绝状态时,点击编辑按钮可以时为强制修改状态
+  const [forceModify, setForceModify] = useState(false);
+
   //是否补充协议,是的话需要填合同编号
   const is_supplement = Form.useWatch('is_supplement', form);
 
@@ -117,25 +118,25 @@ const ContractModal = (props) => {
   const formData = [
     {
       name: '是否本部',
-      id: 'DDSelectField_4fbddb04-9b4f-4281-991b-5047f835fb9d',
+      id: 'DDSelectField_4ad8bda8-60ce-428b-88a3-bf1a18c24a50',
       type: 'DDSelectField',
       value: ['是'],
     },
     {
       name: '合同归档部门',
-      id: 'DDSelectField_1235c6b9-9d74-4856-a62d-6ca1bb9716a6',
+      id: 'DDSelectField_3b661423-9fb8-4498-9eda-bcadf2d98473',
       type: 'DDSelectField',
       value: ['财务部'],
     },
     {
       name: '合同编码',
-      id: 'TextField_1a01000b-4458-4dfb-bd13-74a74e7a33e5',
+      id: 'TextField_f73531d8-c2c0-4769-a8ef-68b2eae2dc3a',
       type: 'TextField',
       value: ['1'],
     },
     {
       name: '提审类型',
-      id: 'DDSelectField_c79e124c-c933-4ea1-b799-faceaf830a9b',
+      id: 'DDSelectField_bed77d5f-d02c-4f1d-98bf-0638245a3331',
       type: 'DDSelectField',
       value: ['1'],
     },
@@ -143,20 +144,9 @@ const ContractModal = (props) => {
 
   //计算审批流数据
   const advance = {
-    flow_id: 40,
+    flow_id: 47,
     form_list: null,
-    // node_level_id:0,
-    // id:0,
-    // project_id:0,
-    // cur_template_node_id:0,
-    // next_template_node_id:0,
-    // template_node_id:0,
-    // flow_path:null,
-    // template_id:0,
-    // cur_template_id:0,
-    // next_template_id:0,
     formComponentValues: '',
-    // audit_list:[],
   };
 
   //旧审批流兼容
@@ -182,6 +172,15 @@ const ContractModal = (props) => {
 
   const { data: companyData, run: runCompany } = useRequest(queryCompany);
 
+  // 新建合同时,选择本部时,需要用另一个接口请求部门数据
+  const { data: companyDeps, run: runCompanyDeps } = useRequest(queryDepsV2, {
+    manual: true,
+    formatResult: (response) => {
+      console.log(response.data);
+      return response.data;
+    },
+  });
+
   //填写表单时计算审批流接口
   const { run: runAuditList } = useRequest(
     (data) => advanceSubmitNextNode(data),
@@ -206,6 +205,7 @@ const ContractModal = (props) => {
       },
     },
   );
+
   //计算合同编号接口
   const { run: runCode } = useRequest((data) => queryContractCode(data), {
     manual: true,
@@ -215,6 +215,7 @@ const ContractModal = (props) => {
       });
     },
   });
+
   //供应商列表
   const { data: supplierList = [], loading } = useRequest(querySupplierList, {
     defaultParams: [
@@ -233,6 +234,7 @@ const ContractModal = (props) => {
         : [];
     },
   });
+
   //获取OA 归档审批列表
   const { data: auditData, run: runAudit } = useRequest(
     (data) => queryAuditByCode({ ...data, extend_type: 0 }),
@@ -250,6 +252,7 @@ const ContractModal = (props) => {
       },
     },
   );
+
   //获取OA 作废审批列表
   const { data: auditCelData, run: runCalAudit } = useRequest(
     (data) => queryAuditByCode({ ...data, extend_type: 1 }),
@@ -270,7 +273,6 @@ const ContractModal = (props) => {
 
   useEffect(() => {
     if (!visible) {
-      setIsPass(1);
       setDealDisable(false);
       setAuditList([]);
       setCompanyDepList([]);
@@ -279,9 +281,18 @@ const ContractModal = (props) => {
       userListRun();
       depListRun();
       runCompany();
+      runCompanyDeps();
     }
   }, [visible]);
 
+  useEffect(() => {
+    //兼容之前选择的所属部门,用的现在的接口匹配不到部门显示数字的问题
+    if (data?.company_id) {
+      const deps = getDepItemById(data?.company_id)?.children;
+      setCompanyDepList(deps);
+    }
+  }, [data, depList]);
+
   useEffect(() => {
     form.resetFields();
     if (data?.status >= Status.Checking) runAudit({ extend_code: data.code });
@@ -307,23 +318,19 @@ const ContractModal = (props) => {
     if (
       type == Type.add ||
       type == Type.cancel ||
-      data?.status == Status.ReCall
+      data?.status == Status.ReCall ||
+      (data?.status == Status.CheckReject && forceModify)
     )
       return true;
-    let currentAuditUserID;
-    if (data?.status == Status.Checking && auditData) {
-      const { OaAuditList, audit_status } = auditData;
-      currentAuditUserID = OaAuditList[audit_status]?.auditor;
-    } else if (data?.status == Status.CalChecking && auditCelData) {
-      const { OaAuditList, audit_status } = auditCelData;
-      currentAuditUserID = OaAuditList[audit_status]?.auditor;
-    }
-    if (user.ID == currentAuditUserID) return true;
-    return false;
-  }, [user, data, auditData, auditCelData]);
+  }, [data, type, forceModify]);
 
   useEffect(() => {
-    if (type !== Type.add && data?.status !== Status.ReCall) return;
+    if (
+      type !== Type.add &&
+      data?.status !== Status.ReCall &&
+      data?.status !== Status.CheckReject
+    )
+      return;
     const newCompony = company || data?.company_id; //recall状态时compony是空, 需要用data?.company_id
     if (!newCompony) {
       setCompanyDepList([]);
@@ -331,30 +338,26 @@ const ContractModal = (props) => {
       return;
     }
     const deps = getDepItemById(newCompony)?.children;
-    if (deps) setCompanyDepList(deps);
+    deps ? setCompanyDepList(deps) : setCompanyDepList([]);
     const item = companyData?.find((item) => item.ID == newCompony);
     if (item?.Flag == 1) {
       //公司为本部 经办人为自己并不可编辑 合同存档部门从财务和行政部选
       setDealDisable(false);
       setArchivesDepList(archivesOptions);
       form.setFieldsValue({ deal_by: user?.CName });
+      // 公司为本部时,使用另一个接口获取部门数据
+      companyDeps ? setCompanyDepList(companyDeps) : setCompanyDepList([]);
     } else {
       //公司为分子公司 经办人为手动输入 合同存档部门从所选分子公司的子部门选择
       setDealDisable(true);
       setArchivesDepList(deps);
       form.setFieldsValue({ deal_by: '' });
     }
-  }, [company, data]);
+  }, [company, data, forceModify]);
 
   //获取合同编号逻辑 只有新增才请求
   useEffect(() => {
-    if (
-      //&& data?.status !== Status.ReCall
-      type !== Type.add ||
-      !company ||
-      !dep_id
-    )
-      return;
+    if (type !== Type.add || !company || !dep_id) return;
     const item = companyData?.find((item) => item.ID == company);
     const dep_code = getDepItemById(dep_id)?.Code;
     if (item) {
@@ -370,7 +373,12 @@ const ContractModal = (props) => {
 
   //获取审批流逻辑
   useEffect(() => {
-    if (type !== Type.add && data?.status !== Status.ReCall) return;
+    if (
+      type !== Type.add &&
+      data?.status !== Status.ReCall &&
+      data?.status !== Status.CheckReject
+    )
+      return;
     const param = { ...advance };
     let formValues = [];
     const item = companyData?.find((item) => item.ID == company);
@@ -384,8 +392,14 @@ const ContractModal = (props) => {
     runAuditList(param);
   }, [company, archives_dep]);
 
+  //根据项目名称填充项目编号逻辑
   useEffect(() => {
-    if (type !== Type.add && data?.status !== Status.ReCall) return;
+    if (
+      type !== Type.add &&
+      data?.status !== Status.ReCall &&
+      data?.status !== Status.CheckReject
+    )
+      return;
     const project_code = projectList?.find(
       (item) => item.project_name == project_name,
     )?.project_full_code;
@@ -395,15 +409,24 @@ const ContractModal = (props) => {
       form.setFieldsValue({ project_code: '' });
     }
   }, [project_name]);
+
   const supplyList = useMemo(() => {
     return companyData ? [...companyData, ...supplierList] : supplierList;
   }, [companyData, supplierList]);
 
   const disableds = useMemo(() => {
-    if (data?.status == Status.ReCall) return { contract: false, recall: true };
-    if (data?.status > Status.None) return { contract: true, recall: true };
+    // 当合同处于审核拒绝状态时,通过修改按钮可强制修改合同并重新进入审核
+    if (forceModify && data?.status == Status.CheckReject) {
+      return { contract: false, recall: false };
+    }
+    // if (data?.status == Status.ReCall) {
+    //   return { contract: false, recall: true };
+    // }
+    if (data?.status > Status.None) {
+      return { contract: true, recall: true };
+    }
     return { contract: false, recall: false };
-  }, [visible]);
+  }, [visible, forceModify]);
 
   const UploadProps = {
     action: `/api/contract/v1/attach`,
@@ -418,6 +441,7 @@ const ContractModal = (props) => {
       }
     },
   };
+
   const UploadPropsExtend = {
     action: `/api/contract/v1/attach`,
     headers: {
@@ -480,7 +504,10 @@ const ContractModal = (props) => {
           code: data?.code,
         };
         handleOk(result, Type.cancel, form, audit_list);
-      } else if (data?.status == Status.ReCall) {
+      } else if (
+        data?.status == Status.ReCall ||
+        data?.status == Status.CheckReject
+      ) {
         const form = getAuditData(values, '1');
         const audit_list = auditList.map((item) => item.value);
         values.effect_on = dayjs(values.effect_on).format(FORMAT);
@@ -502,24 +529,32 @@ const ContractModal = (props) => {
         values.created_by = user?.ID;
         values.id = data?.id;
         handleOk(values, Type.add, form, audit_list);
-      } else if (data?.status == Status.Checking) {
-        let result = {
-          id: auditData?.id,
-          status: values.is_pass,
-          desc: '',
-        };
-        handleOk(result, Type.check, data?.status);
-      } else if (data?.status == Status.CalChecking) {
-        let result = {
-          id: auditCelData?.id,
-          status: values.is_pass,
-          desc: '',
-        };
-        handleOk(result, Type.check, data?.status);
       }
     });
   };
 
+  const handleSaveDraft = () => {
+    let values = form.getFieldsValue();
+    if (!values.name) {
+      message.error('请填写合同名称!');
+      return;
+    }
+    Object.keys(values).forEach((key) => {
+      if (Array.isArray(values[key]))
+        values[key].length == 0
+          ? delete values[key]
+          : (values[key] = JSON.stringify(values[key]));
+    });
+    if (values.effect_on)
+      values.effect_on = dayjs(values.effect_on).format(FORMAT);
+    const params = {
+      name: values.name,
+      content: JSON.stringify(values),
+    };
+    if (data?.id) params.id = data?.id;
+    handleOk(params, Type.save);
+  };
+
   const getDepItemById = (id) => {
     const fun = (list) => {
       for (let i = 0; i < list.length; i++) {
@@ -547,16 +582,39 @@ const ContractModal = (props) => {
   const renderFooter = () => {
     return (
       <Space>
-        {data?.status == Status.Checking && type !== Type.check && (
+        {data?.status == Status.Checking && (
           <Button onClick={() => handlerReCall(auditData?.id)}>撤回</Button>
         )}
-        <Button onClick={handleCancel}>取消</Button>
+        <Button
+          onClick={() => {
+            setForceModify(false);
+            form.resetFields();
+            handleCancel();
+          }}
+        >
+          取消
+        </Button>
+        {data?.status == Status.CheckReject && !forceModify && (
+          <Button
+            onClick={() => {
+              setForceModify(true);
+            }}
+          >
+            修改
+          </Button>
+        )}
+        {type == Type.add && (
+          <Button type="primary" onClick={handleSaveDraft}>
+            保存草稿
+          </Button>
+        )}
         <Button type="primary" onClick={handleSubmit} disabled={!isSuper}>
           提交
         </Button>
       </Space>
     );
   };
+
   return (
     <>
       <Modal
@@ -588,7 +646,10 @@ const ContractModal = (props) => {
                 name="company_id"
                 label="所属公司:"
                 tooltip="请选择该存档合同所属公司"
-                initialValue={data?.company_id}
+                initialValue={
+                  //不可编辑的时候直接赋值为company_name
+                  !disableds.contract ? data?.company_id : data?.company_name
+                }
                 rules={[
                   {
                     required: true,
@@ -600,7 +661,7 @@ const ContractModal = (props) => {
                   showSearch
                   style={{ width: '100%' }}
                   placeholder="请选择"
-                  disabled={disableds.contract || disableds.recall}
+                  disabled={disableds.contract}
                   filterOption={(input, option) =>
                     (option?.label ?? '')
                       .toLowerCase()
@@ -627,6 +688,12 @@ const ContractModal = (props) => {
                 name="dep_id"
                 label="所属部门:"
                 initialValue={data?.dep_id}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择所属部门',
+                  },
+                ]}
               >
                 <TreeSelect
                   style={{ width: '100%' }}
@@ -638,9 +705,16 @@ const ContractModal = (props) => {
                     value: 'ID',
                     children: 'children',
                   }}
-                  disabled={disableds.contract || disableds.recall}
+                  disabled={disableds.contract}
                   dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-                  treeData={companyDepList}
+                  treeData={
+                    data?.dep_id
+                      ? [
+                          ...companyDepList,
+                          { Name: data.dep_name, ID: data?.dep_id },
+                        ]
+                      : companyDepList
+                  }
                 />
               </Form.Item>
             </Col>
@@ -709,7 +783,7 @@ const ContractModal = (props) => {
                   },
                 ]}
               >
-                <Radio.Group disabled={disableds.contract || disableds.recall}>
+                <Radio.Group disabled={disableds.contract}>
                   <Radio value={1}>是</Radio>
                   <Radio value={0}>否</Radio>
                 </Radio.Group>
@@ -731,7 +805,9 @@ const ContractModal = (props) => {
               <Form.Item
                 name="effect_on"
                 label="合同签订日期:"
-                initialValue={data?.effect_on}
+                initialValue={
+                  data?.effect_on ? dayjs(data?.effect_on, FORMAT) : ''
+                }
                 tooltip="合同主体各方签字盖章完成之日,以最后签字盖章的为准"
                 rules={[
                   {
@@ -740,14 +816,10 @@ const ContractModal = (props) => {
                   },
                 ]}
               >
-                {type == Type.add ? (
-                  <DatePicker
-                    style={{ width: '100%' }}
-                    disabled={disableds.contract}
-                  />
-                ) : (
-                  <Input disabled={disableds.contract} />
-                )}
+                <DatePicker
+                  style={{ width: '100%' }}
+                  disabled={disableds.contract}
+                />
               </Form.Item>
               <Form.Item
                 name="project_name"
@@ -786,18 +858,17 @@ const ContractModal = (props) => {
                   },
                 ]}
               >
-                <TreeSelect
+                <Select
                   style={{ width: '100%' }}
                   placeholder="请选择"
                   showSearch
                   allowClear
-                  fieldNames={{
-                    label: 'Name',
-                    value: 'Name',
-                    children: 'children',
-                  }}
-                  dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-                  treeData={supplyList}
+                  options={supplyList?.map((item) => {
+                    return {
+                      label: item.Name,
+                      value: item.Name,
+                    };
+                  })}
                   disabled={disableds.contract}
                 />
               </Form.Item>
@@ -820,10 +891,7 @@ const ContractModal = (props) => {
                     : []
                 }
               >
-                <Input
-                  placeholder="请填写"
-                  disabled={disableds.contract || disableds.recall}
-                />
+                <Input placeholder="请填写" disabled={disableds.contract} />
               </Form.Item>
               <Form.Item
                 name="code"
@@ -872,19 +940,18 @@ const ContractModal = (props) => {
                   },
                 ]}
               >
-                <TreeSelect
+                <Select
                   style={{ width: '100%' }}
                   placeholder="请选择"
                   showSearch
                   allowClear
+                  options={supplyList?.map((item) => {
+                    return {
+                      label: item.Name,
+                      value: item.Name,
+                    };
+                  })}
                   disabled={disableds.contract}
-                  fieldNames={{
-                    label: 'Name',
-                    value: 'Name',
-                    children: 'children',
-                  }}
-                  dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-                  treeData={supplyList}
                 />
               </Form.Item>
             </Col>
@@ -893,22 +960,21 @@ const ContractModal = (props) => {
             name="party_c"
             label="丙方(及其他):"
             tooltip="可多选。合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
-            initialValue={data?.party_c ? data?.party_c.split(',') : []}
+            initialValue={data?.party_c ? data?.party_c?.split(',') : []}
             labelCol={{ span: 4 }}
           >
-            <TreeSelect
+            <Select
               style={{ width: '100%' }}
               placeholder="请选择"
+              mode="multiple"
               showSearch
-              multiple
               allowClear
-              fieldNames={{
-                label: 'Name',
-                value: 'Name',
-                children: 'children',
-              }}
-              dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-              treeData={supplyList}
+              options={supplyList?.map((item) => {
+                return {
+                  label: item.Name,
+                  value: item.Name,
+                };
+              })}
               disabled={disableds.contract}
             />
           </Form.Item>
@@ -938,7 +1004,9 @@ const ContractModal = (props) => {
                 }
                 initialValue={attachData.attach}
               >
-                {type == Type.add || data?.status == Status.ReCall ? (
+                {type == Type.add ||
+                data?.status == Status.ReCall ||
+                forceModify ? (
                   <Upload {...UploadProps}>
                     <Button icon={<CloudUploadOutlined />}>Upload</Button>
                   </Upload>
@@ -970,7 +1038,7 @@ const ContractModal = (props) => {
                 <Select
                   style={{ width: '100%' }}
                   options={archivesDepList?.map((item) => {
-                    return { label: item.Name, value: item.ID };
+                    return { label: item.Name, value: item.Name };
                   })}
                   disabled={disableds.contract}
                 />
@@ -998,27 +1066,29 @@ const ContractModal = (props) => {
                   </div>
                 }
               >
-                {type == Type.add ? (
+                {type == Type.add || forceModify ? (
                   <Upload {...UploadPropsExtend}>
                     <Button icon={<CloudUploadOutlined />}>Upload</Button>
                   </Upload>
                 ) : (
                   <ul>
                     {data?.attach_extend &&
-                      JSON.parse(data?.attach_extend)?.map((item, idx) => (
-                        <li key={`${idx}_${item.name}`}>
-                          <a onClick={() => handlePreViewSingle(item)}>
-                            {item.name}
-                          </a>
-                        </li>
-                      ))}
+                      JSON.parse(data?.attach_extend)
+                        ?.filter((item) => item)
+                        .map((item, idx) => (
+                          <li key={`${idx}_${item.name}`}>
+                            <a onClick={() => handlePreViewSingle(item)}>
+                              {item.name}
+                            </a>
+                          </li>
+                        ))}
                   </ul>
                 )}
               </Form.Item>
             </Col>
           </Row>
 
-          {data?.status >= Status.Checking && (
+          {data?.status >= Status.Checking && !forceModify && (
             <>
               <ModuleTitle title="归档流程" />
               <div className={styles.modelItem}>
@@ -1026,58 +1096,6 @@ const ContractModal = (props) => {
               </div>
             </>
           )}
-          {isSuper && data.status == Status.Checking && (
-            <>
-              <ModuleTitle title="审核情况" />
-              <Row>
-                <Col span={10} offset={1}>
-                  <Form.Item
-                    name="check_by"
-                    initialValue={user?.CName}
-                    label="审核人:"
-                  >
-                    <Input disabled />
-                  </Form.Item>
-                  <Form.Item name="is_pass" initialValue={1} label="审核意见:">
-                    <Select
-                      onChange={(e) => {
-                        setIsPass(e);
-                      }}
-                      style={{ width: '100%' }}
-                      options={[
-                        {
-                          value: 1,
-                          label: '同意',
-                        },
-                        {
-                          value: 2,
-                          label: '拒绝',
-                        },
-                      ]}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={10}>
-                  <Form.Item
-                    name="check_date"
-                    initialValue={dayjs().format(FORMAT)}
-                    label="审核时间:"
-                  >
-                    <Input disabled />
-                  </Form.Item>
-                </Col>
-              </Row>
-              {isPass == 2 && (
-                <Form.Item
-                  name="check_desc"
-                  label="拒绝原因:"
-                  labelCol={{ span: 4 }}
-                >
-                  <Input.TextArea />
-                </Form.Item>
-              )}
-            </>
-          )}
           {(type == Type.cancel || data?.status >= Status.CalChecking) && (
             <>
               <ModuleTitle title="作废信息" />
@@ -1124,59 +1142,7 @@ const ContractModal = (props) => {
               </div>
             </>
           )}
-          {isSuper && data.status == Status.CalChecking && (
-            <>
-              <ModuleTitle title="审核情况" />
-              <Row>
-                <Col span={10} offset={1}>
-                  <Form.Item
-                    name="cancel_check_by"
-                    initialValue={user?.CName}
-                    label="审核人:"
-                  >
-                    <Input disabled />
-                  </Form.Item>
-                  <Form.Item name="is_pass" initialValue={1} label="审核意见:">
-                    <Select
-                      onChange={(e) => {
-                        setIsPass(e);
-                      }}
-                      style={{ width: '100%' }}
-                      options={[
-                        {
-                          value: 1,
-                          label: '同意',
-                        },
-                        {
-                          value: 0,
-                          label: '拒绝',
-                        },
-                      ]}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={10}>
-                  <Form.Item
-                    name="check_date"
-                    initialValue={dayjs().format(FORMAT)}
-                    label="审核时间:"
-                  >
-                    <Input disabled />
-                  </Form.Item>
-                </Col>
-              </Row>
-              {!isPass && (
-                <Form.Item
-                  name="cancel_check_result"
-                  label="拒绝原因:"
-                  labelCol={{ span: 4 }}
-                >
-                  <Input.TextArea />
-                </Form.Item>
-              )}
-            </>
-          )}
-          {(type == Type.add || data?.status == Status.ReCall) &&
+          {(type == Type.add || data?.status == Status.ReCall || forceModify) &&
             auditList.length > 0 && (
               <>
                 <ModuleTitle title="审批流程" />

+ 438 - 0
src/pages/ContractManager/detail.js

@@ -0,0 +1,438 @@
+import ModuleTitle from '@/components/ModuleTitle/moduleTitle';
+import FileViewerModal from '@/components/FileViewerNew';
+import {
+  Divider,
+  Form,
+  Modal,
+  Row,
+  Col,
+  Input,
+  Radio,
+  InputNumber,
+  Card,
+} from 'antd';
+import dayjs from 'dayjs';
+import { useEffect, useState } from 'react';
+import { useParams, useRequest, useNavigate } from 'umi';
+import { Status } from './component/Modal';
+import styles from './index.less';
+import AuditSteps from './component/AuditSteps';
+import { queryAuditByCode } from '../../services/contract';
+
+const ContractDetail = ({ data }) => {
+  const [form] = Form.useForm();
+  const FORMAT = 'YYYY-MM-DD';
+
+  const [fileViewerVisible, setFileViewerVisible] = useState(false);
+  const [fileViewerData, setFileViewerData] = useState();
+  const [attachData, setAttachData] = useState({
+    attach: [],
+    attach_extend: [],
+  });
+
+  useEffect(() => {
+    form.resetFields();
+    if (data?.status >= Status.Checking) runAudit({ extend_code: data.code });
+    let result = { attach: [], attach_extend: [] };
+    if (data?.attach) {
+      let att = JSON.parse(data.attach);
+      result.attach = att.map((item, idx) => {
+        return { ...item, uid: idx, status: 'done' };
+      });
+    }
+    if (data?.attach_extend) {
+      let att = JSON.parse(data.attach_extend);
+      result.attach_extend = att.map((item, idx) => {
+        return { ...item, uid: idx, status: 'done' };
+      });
+    }
+    setAttachData(result);
+  }, [data]);
+
+  //获取OA 归档审批列表
+  const { data: auditData, run: runAudit } = useRequest(
+    (data) => queryAuditByCode({ ...data, extend_type: 0 }),
+    {
+      manual: true,
+      formatResult: (res) => {
+        if (res?.data) {
+          return res.data;
+        } else {
+          if (data?.status == Status.CheckReject) {
+            return { ...oldAuditList, audit_status: 2 };
+          }
+          return oldAuditList;
+        }
+      },
+    },
+  );
+
+  const handlePreViewSingle = (data) => {
+    if (!data) return;
+    const arr = data.name.split('.');
+    const type = arr[arr.length - 1];
+    const dataItem = { url: data.url, name: data.name, type };
+    setFileViewerData(dataItem);
+    setFileViewerVisible(true);
+  };
+
+  return (
+    <>
+      <Card title={data?.status == Status.Checking ? '归档审批' : '作废审批'}>
+        <Form
+          form={form}
+          // initialValues={data}
+          labelCol={{ span: 7 }}
+          wrapperCol={{ span: 17 }}
+        >
+          <ModuleTitle title="存档人信息" />
+          <Row>
+            <Col span={10} offset={1}>
+              <Form.Item
+                name="created_name"
+                initialValue={data?.created_name}
+                label="存档人:"
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="company_name"
+                label="所属公司:"
+                tooltip="请选择该存档合同所属公司"
+                initialValue={data?.company_name}
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写所属公司',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+            <Col span={10}>
+              <Form.Item
+                name="created_on"
+                initialValue={data?.created_on || dayjs().format(FORMAT)}
+                label="存档时间:"
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="dep_id"
+                label="所属部门:"
+                initialValue={data?.dep_name}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择所属部门',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+          </Row>
+          <ModuleTitle title="经办人信息" />
+          <Row>
+            <Col span={10} offset={1}>
+              <Form.Item
+                name="deal_by"
+                label="经办人:"
+                tooltip="经办人应负责合同审批流程、签字盖章、合同原件存档和电子档案存档。母公司的经办人为OA审批提交人,也是存档人。子公司经办人由子公司合同专员填写,一般是合同审批时的提交人或者是合同实际执行的负责人"
+                initialValue={data?.deal_by}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择经办人',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+            <Col span={10}>
+              <Form.Item
+                name="created_dep"
+                label="签约承办部门:"
+                tooltip="请选择该存档合同的实际履行部门,一般为经办人所在部门"
+                initialValue={data?.created_dep}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择签约承办部门',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+          </Row>
+          <ModuleTitle title="合同信息" />
+
+          <Row>
+            <Col span={10} offset={1}>
+              <Form.Item
+                name="is_supplement"
+                label="是否补充协议:"
+                tooltip="合同名称"
+                initialValue={0}
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写合同名称',
+                  },
+                ]}
+              >
+                <Radio.Group disabled>
+                  <Radio value={1}>是</Radio>
+                  <Radio value={0}>否</Radio>
+                </Radio.Group>
+              </Form.Item>
+              <Form.Item
+                name="name"
+                label="合同名称:"
+                tooltip="请与OA审批时填写的合同名称一致"
+                initialValue={data?.name}
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写合同名称',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="effect_on"
+                label="合同签订日期:"
+                initialValue={data?.effect_on}
+                tooltip="合同主体各方签字盖章完成之日,以最后签字盖章的为准"
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写合同名称',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="project_name"
+                label="项目名称:"
+                tooltip="不涉及项目请选“日常项目”"
+                initialValue={data?.project_name}
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写项目名称',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="party_a"
+                label="甲方:"
+                tooltip="合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
+                initialValue={data?.party_a}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择甲方',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+            <Col span={10}>
+              <Form.Item
+                style={{ opacity: data?.is_supplement ? 1 : 0 }}
+                name="parent_code"
+                tooltip="请先查询原合同编号,原合同未录入本系统的,需先录入存档。"
+                initialValue={data?.parent_code}
+                label="原合同编号:"
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="code"
+                tooltip="合同编号按《合同管理办法》的合同编码规则编号。"
+                initialValue={data?.code}
+                label="合同编号:"
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                label="合同总价款:"
+                name="amount"
+                tooltip="请与OA审批时填写的“合同金额”一致。不涉及金额填“0”"
+                initialValue={data?.amount}
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入合同总价款',
+                  },
+                ]}
+              >
+                <InputNumber
+                  style={{ width: '100%' }}
+                  precision={2}
+                  addonAfter="万元"
+                  disabled
+                />
+              </Form.Item>
+
+              <Form.Item
+                name="project_code"
+                initialValue={data?.project_code}
+                label="项目编号:"
+              >
+                <Input disabled />
+              </Form.Item>
+              <Form.Item
+                name="party_b"
+                label="乙方:"
+                tooltip="合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
+                initialValue={data?.party_b}
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择乙方',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+          </Row>
+          <Form.Item
+            name="party_c"
+            label="丙方(及其他):"
+            tooltip="可多选。合同主体可以下拉选择,可选项需要经办人在“主页--供应商管理”中创建。经办人可以维护和更新供应商信息。"
+            initialValue={data?.party_c ? data?.party_c.split(',') : []}
+            labelCol={{ span: 4 }}
+          >
+            <Input disabled />
+          </Form.Item>
+          <Form.Item
+            name="perform"
+            initialValue={data?.perform}
+            label="合同履行情况:"
+            labelCol={{ span: 4 }}
+          >
+            <Input.TextArea disabled />
+          </Form.Item>
+          <Row>
+            <Col span={10} offset={1}>
+              <Form.Item
+                label="合同及合同附件上传:"
+                tooltip="请上传合同正式盖章文本的扫描件(含技术协议、质保承诺等附件),不得用照片、图片格式,不得遗漏附件"
+                name="attach"
+                initialValue={attachData.attach}
+              >
+                <ul>
+                  {data?.attach &&
+                    JSON.parse(data?.attach)?.map((item, idx) => (
+                      <li key={`${idx}_${item.name}`}>
+                        <a onClick={() => handlePreViewSingle(item)}>
+                          {item.name}
+                        </a>
+                      </li>
+                    ))}
+                </ul>
+              </Form.Item>
+              <Form.Item
+                name="archives_dep"
+                initialValue={data?.archives_dep}
+                label="合同原件存档部门:"
+                tooltip="母公司财务部和采购部门的合同请选择“财务部”,其他部门请选择“行政部”,子公司合同选择“综合管理部”"
+                rules={[
+                  {
+                    required: true,
+                    message: '请选择合同原件存档部门',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </Col>
+            <Col span={10}>
+              <Form.Item
+                name="attach_extend"
+                label="合同相关资料上传:"
+                initialValue={attachData.attach_extend}
+                tooltip={
+                  <div>
+                    依据《合同管理办法》,合同相关资料需要作为合同电子档案的一部分,包括:
+                    <br />
+                    1)合同会审纪要或投资决策通知书(如有);
+                    <br />
+                    2)合同相对方的营业执照等资质证的复印件(首次签约的须加盖公章)、个人身份证复印件(合同一方为自然人时提供);
+                    <br />
+                    3)合同相对方经办人员的授权委托书原件及其身份证复印件(如有);
+                    <br />
+                    4)
+                    涉及房屋或场地租赁的,还应提供房屋及场地的权属证明资料,但如果续签租赁合同,且房屋所有权人没有发生变更的,在附具相关说明后可不再提供上述资料;
+                    <br />
+                    5)其他资料。
+                  </div>
+                }
+              >
+                <ul>
+                  {data?.attach_extend &&
+                    JSON.parse(data?.attach_extend)?.map((item, idx) => (
+                      <li key={`${idx}_${item.name}`}>
+                        <a onClick={() => handlePreViewSingle(item)}>
+                          {item.name}
+                        </a>
+                      </li>
+                    ))}
+                </ul>
+              </Form.Item>
+            </Col>
+          </Row>
+
+          {data?.status > Status.Checking && (
+            <>
+              <ModuleTitle title="归档流程" />
+              <div className={styles.modelItem}>
+                <AuditSteps {...auditData} statusText="已归档" />
+              </div>
+            </>
+          )}
+
+          {data?.status > Status.CalChecking && (
+            <>
+              <ModuleTitle title="作废信息" />
+              <Form.Item
+                name="cancel_desc"
+                label="作废原因:"
+                initialValue={data?.cancel_desc}
+                labelCol={{ span: 4 }}
+                rules={[
+                  {
+                    required: true,
+                    message: '请填写作废原因',
+                  },
+                ]}
+              >
+                <Input disabled />
+              </Form.Item>
+            </>
+          )}
+        </Form>
+      </Card>
+      <FileViewerModal
+        data={fileViewerData}
+        visible={fileViewerVisible}
+        onCancel={() => {
+          setFileViewerVisible(false);
+        }}
+      />
+    </>
+  );
+};
+
+export default ContractDetail;

+ 64 - 46
src/pages/ContractManager/index.jsx

@@ -1,4 +1,4 @@
-import React, { useState, useRef, useEffect } from 'react';
+import React, { useState, useRef, useEffect, useMemo } from 'react';
 import {
   Button,
   DatePicker,
@@ -21,6 +21,7 @@ import {
   queryContractCancelCheck,
   queryContractCheck,
   queryContractDownload,
+  queryContractSaveDraft,
   queryDelById,
   queryGetContractList,
   queryOAReCall,
@@ -33,6 +34,7 @@ import EllipsisText from './component/EllipsisText';
 import { stringify } from 'qs';
 import { audit, createAduit } from '@/services/boom';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
+import DraftModal from './component/DraftModal';
 
 const ConteactManager = (props) => {
   const { dispatch } = props;
@@ -44,9 +46,8 @@ const ConteactManager = (props) => {
     current: 1,
     name: '',
   });
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const [visible, setVisible] = useState(false);
   const [detail, setDetail] = useState({});
   const [data, setData] = useState([]);
@@ -57,6 +58,9 @@ const ConteactManager = (props) => {
   const [fileViewerData, setFileViewerData] = useState();
   const [modal, contextHolder] = Modal.useModal();
 
+  const [draftOpen, setDraftOpen] = useState(false);
+  const oaParamsRef = useRef();
+
   const showBtn = (record, type) => {
     let bool = false;
     switch (type) {
@@ -262,6 +266,8 @@ const ConteactManager = (props) => {
     manual: true,
     onSuccess: () => {
       // message.success('添加成功');
+      createRun(oaParamsRef.current);
+      oaParamsRef.current = null;
       setVisible(false);
       run(searchData);
       modal.info(config);
@@ -284,40 +290,6 @@ const ConteactManager = (props) => {
     },
   });
 
-  // //作废审核
-  // const { run: calCheckRun } = useRequest(
-  //   (data) => queryContractCancelCheck(data),
-  //   {
-  //     manual: true,
-  //     onSuccess: () => {
-  //       message.success('审核成功');
-  //       setVisible(false);
-  //       run(searchData);
-  //     },
-  //     onError: () => {
-  //       message.success('审核失败');
-  //     },
-  //   },
-  // );
-
-  // //审核合同
-  // const { run: runCheck, loading: checkLoading } = useRequest(
-  //   (data) => queryContractCheck(data),
-  //   {
-  //     manual: true,
-  //     onSuccess: () => {
-  //       // conAuditRun({ multi_status: '1,4', currentPage: 1, page_size: 10 });
-  //       // conAuditedRun({ check_by: user.CName });
-  //       setVisible(false);
-  //       run(searchData);
-  //       message.success('审核成功');
-  //     },
-  //     onErroe: () => {
-  //       message.error('审核失败');
-  //     },
-  //   },
-  // );
-
   //审核合同
   const { run: runOACheck } = useRequest(audit, {
     manual: true,
@@ -332,7 +304,7 @@ const ConteactManager = (props) => {
       setVisible(false);
       message.success('审核成功');
     },
-    onErroe: () => {
+    onError: () => {
       message.error('审核失败');
     },
   });
@@ -344,12 +316,24 @@ const ConteactManager = (props) => {
 
   //发起OA审批
   const { run: createRun } = useRequest(
-    (data) => createAduit({ ...data, flow_id: 40, cc_list: [], files: '' }),
+    (data) => createAduit({ ...data, flow_id: 47, cc_list: [], files: '' }),
     {
       manual: true,
     },
   );
 
+  //保存草稿
+  const { run: saveDraftRun } = useRequest(
+    (data) => queryContractSaveDraft(data),
+    {
+      manual: true,
+      onSuccess: (res) => {
+        setVisible(false);
+        message.success('保存成功');
+      },
+    },
+  );
+
   const handleDelete = (id) => {
     modal.confirm({
       icon: <ExclamationCircleOutlined />,
@@ -410,6 +394,14 @@ const ConteactManager = (props) => {
     );
   };
 
+  const handleDraftOpen = (data) => {
+    console.log(data);
+    setDraftOpen(false);
+    typeRef.current = Type.add;
+    setDetail(data);
+    setVisible(true);
+  };
+
   const handleQueryChildren = async (req) => {
     const res = await queryGetContractList(req);
     if (res?.data?.list) {
@@ -424,13 +416,13 @@ const ConteactManager = (props) => {
 
   const handleOk = (data, type, formData = [], audit_list = []) => {
     if (type == Type.add) {
-      editRun(data);
-      createRun({
+      oaParamsRef.current = {
         form: JSON.stringify(formData),
         audit_list,
         extend_code: data.code,
         extend_type: 0, //归档提交
-      });
+      };
+      editRun(data);
     } else if (type == Type.cancel) {
       calRun(data);
       createRun({
@@ -441,12 +433,22 @@ const ConteactManager = (props) => {
       });
     } else if (type == Type.check) {
       runOACheck(data);
+    } else if (type == Type.modify) {
+      calRun(data);
+      createRun({
+        form: JSON.stringify(formData),
+        audit_list,
+        extend_code: data.code,
+        extend_type: 0, //归档提交
+      });
+    } else if (type == Type.save) {
+      saveDraftRun(data);
     }
   };
 
   const handlerReCall = async (id) => {
     modal.confirm({
-      icon: <ExclamationCircleOutlined />,
+      icon: <ExclamationCircleOutlined ined />,
       title: '提示:',
       content: <div>确定撤回合同存档审批!</div>,
       onOk: async () => {
@@ -454,7 +456,9 @@ const ConteactManager = (props) => {
         if (res.code == 200) {
           message.success('撤回成功');
           setVisible(false);
-          run(searchData);
+          setTimeout(() => {
+            run(searchData);
+          }, 1000);
         } else {
           message.success('撤回失败,请重试');
         }
@@ -484,6 +488,7 @@ const ConteactManager = (props) => {
           <Select
             style={{ width: 200 }}
             placeholder="请选择"
+            allowClear
             onChange={(e) => {
               setSearchData({
                 ...searchData,
@@ -541,6 +546,7 @@ const ConteactManager = (props) => {
         </Button>
         <Button
           type="primary"
+          className={styles.searchBtnSty}
           onClick={() => {
             typeRef.current = Type.add;
             setDetail({});
@@ -549,6 +555,9 @@ const ConteactManager = (props) => {
         >
           新增
         </Button>
+        <Button type="primary" onClick={() => setDraftOpen(true)}>
+          草稿箱
+        </Button>
         <Button
           type="primary"
           className={styles.exportBtnSty}
@@ -567,7 +576,11 @@ const ConteactManager = (props) => {
           console.log(expanded, record);
           if (expanded) handleQueryChildren({ is_parent: record.id });
         }}
-        pagination={{ ...pagination, onChange: onPageChange }}
+        pagination={{
+          ...pagination,
+          showSizeChanger: false,
+          onChange: onPageChange,
+        }}
       />
       <ContractModal
         detail={detail}
@@ -587,6 +600,11 @@ const ConteactManager = (props) => {
           setFileViewerVisible(false);
         }}
       />
+      <DraftModal
+        open={draftOpen}
+        onOk={handleDraftOpen}
+        onCancel={() => setDraftOpen(false)}
+      />
       {contextHolder}
     </PageContent>
   );

+ 3 - 4
src/pages/FileManagement/index.js

@@ -60,9 +60,8 @@ const { RangePicker } = DatePicker;
 function FileManagement(props) {
   const [form] = Form.useForm();
   const [modal, contextHolder] = Modal.useModal();
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const { userList, run: userListRun } = useModel('userList');
   const [tableData, setTableData] = useState([]);
   const [visible, setVisible] = useState(false);
@@ -335,7 +334,7 @@ function FileManagement(props) {
     {
       title: '上传时间',
       align: 'center',
-      dataIndex: 'create_time',
+      dataIndex: 'created_on',
       render: (text) => dayjs(text).format('YYYY-MM-DD'),
     },
     {

+ 6 - 6
src/pages/Flow/Audit.js

@@ -17,9 +17,8 @@ function Audit(props) {
   } = props;
   const [tabActiveKey, setTabActiveKey] = useState('1');
   const ref = useRef();
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const permission = user?.Permission || {};
 
   const curItem = useMemo(() => {
@@ -120,10 +119,10 @@ function Audit(props) {
         },
       ]}
     >
-      {tabActiveKey == 1 && (
-        <AuditForm value={formData} onChange={(values) => onChange(values)} />
+      {tabActiveKey === '1' && (
+        <AuditForm value={formData} onChange={onChange} />
       )}
-      {tabActiveKey == 2 && (
+      {tabActiveKey === '2' && (
         <Flow
           meta={{ type: 'edit', editMode, flowId: curItem.id }}
           flowDetail={flowDetail}
@@ -133,6 +132,7 @@ function Audit(props) {
     </PageContent>
   );
 }
+
 export default connect(({ flow, loading, user, xflow }) => ({
   roleList: flow.roleList,
   loading: loading.effects,

+ 38 - 10
src/pages/Flow/OaAuditDetail.js

@@ -1,18 +1,31 @@
 // 审批详情
-import React, { useState, useMemo } from 'react';
-import { Steps, Button, Tooltip, message } from 'antd';
-import { useParams, useRequest, useModel } from 'umi';
+import React, { useState, useMemo, useEffect } from 'react';
+import { Steps, Button, Tooltip, message, Spin } from 'antd';
+import { useParams, useRequest, useModel, useLocation } from 'umi';
 import AuditModal from './components/AuditModal';
 import FormAndFilesNode from './components/FormAndFilesNode';
 import { queryAuditDetail, updateAuditList } from '@/services/boom';
+import { queryGetContractList } from '@/services/contract';
 import PageContent from '@/components/PageContent';
 import SignModal from './components/SignModal';
+import ContractDetail from '../ContractManager/detail';
+import { Type } from '../Profile';
+import { queryContractDetail } from '../../services/contract';
 
-function OaAuditDetail(props) {
+function OaAuditDetail() {
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const [auditVisible, setAuditVisible] = useState(false);
-  const { oaId, id } = useParams();
+  const location = useLocation();
+  const {
+    state: { id, type, code },
+  } = location;
   const [visible, setVisible] = useState(false);
 
+  useEffect(() => {
+    if (type == Type.CON) runCon({ code });
+  }, [type]);
+
   const { data, loading, refresh } = useRequest(queryAuditDetail, {
     defaultParams: [{ id }],
   });
@@ -24,10 +37,21 @@ function OaAuditDetail(props) {
     audit_status,
     AuditorInfo,
   } = data || {};
-  if (OaAuditList) console.log(JSON.stringify(OaAuditList));
+  // if (OaAuditList) console.log(JSON.stringify(OaAuditList));
+
+  //请求列表
   const {
-    initialState: { user },
-  } = useModel('@@initialState');
+    data: conData,
+    run: runCon,
+    loading: conLoading,
+  } = useRequest((data) => queryContractDetail(data), {
+    manual: true,
+    formatResult: (res) => {
+      return res?.data?.detail;
+    },
+    onSuccess: (res) => {},
+  });
+  // console.log(conData);
 
   const getDescription = (node) => {
     let str = node?.AuditRoleInfo
@@ -103,7 +127,7 @@ function OaAuditDetail(props) {
   }, [user, data]);
 
   return (
-    <PageContent extra={btns} loading={loading}>
+    <PageContent extra={btns} loading={loading && conLoading}>
       <Steps
         style={{ marginBottom: 20 }}
         current={audit_status == 3 ? OaAuditList?.length : current_seq - 1}
@@ -113,7 +137,11 @@ function OaAuditDetail(props) {
           description: getDescription(item),
         }))}
       ></Steps>
-      <FormAndFilesNode formData={form} fileList={Files} />
+      {type == Type.OA ? (
+        <FormAndFilesNode formData={form} fileList={Files} />
+      ) : (
+        <ContractDetail data={conData} />
+      )}
 
       <AuditModal
         id={id}

+ 171 - 10
src/pages/Flow/OaDetail.js

@@ -12,11 +12,15 @@ import {
   queryLeader,
 } from '@/services/boom';
 import { useParams, useRequest, useNavigate } from 'umi';
+import table from '../Table';
 
 const OaDetail = () => {
   const [form] = Form.useForm();
+
   const [approvalProcess, setApprovalProcess] = useState([]);
   const [auditCheck, setAuditCheck] = useState([]);
+  const [tableData, setTableData] = useState([]);
+
   const { oaId } = useParams();
   const formValueRef = useRef({
     form: '',
@@ -87,31 +91,186 @@ const OaDetail = () => {
     run(params);
   };
 
-  const submit = () => {
+  const handleTableValChange = (value, id, label) => {
+    let ids = id.split(';');
+    let [rowIndex, colIndex] = ids[0].split(',').map((item) => Number(item));
+    let [columnID, tableID] = ids[1].split('>');
+    let [columnLabel, tableLabel] = label.split('>');
+
+    const cell = {
+      name: columnLabel,
+      id: columnID,
+      type: columnID.split('_')[0],
+      value: [value],
+    };
+    // 组装可能用到的数据
+    const cols = [];
+    cols[colIndex] = cell;
+    const rows = [];
+    rows[rowIndex] = cols;
+    // 如果已经有数据
+    let oldTableData = [];
+    // 这里不知道为什么不能直接读取state(tableData)
+    setTableData((prevState) => {
+      oldTableData = prevState;
+      return prevState;
+    });
+    if (oldTableData && oldTableData.length > 0) {
+      let table = oldTableData.find((item) => item.id === tableID);
+      // 如果某个表格数据存在
+      if (table) {
+        const oldRows = table.value;
+        // 如果某个表格的行数据存在
+        if (oldRows) {
+          let odlCols = oldRows[rowIndex];
+          // 如果某个表格的某个行数据存在
+          if (odlCols) {
+            // 记录可编辑控件
+            table.value[rowIndex][colIndex] = cell;
+            // 不可编辑控件
+            table.value[rowIndex] = addUnEditableColumn(
+              table.value[rowIndex],
+              tableID,
+            );
+            const newTableData = oldTableData.map((item) => {
+              if (item.id === table.id) {
+                return table;
+              }
+              return item;
+            });
+
+            setTableData(newTableData);
+          } else {
+            // 如果某个表格的某个行数据不存在
+            // 写入可编辑控件
+            table.value[rowIndex] = cols;
+            // 写入不可编辑控件的值
+            table.value[rowIndex] = addUnEditableColumn(
+              table.value[rowIndex],
+              tableID,
+            );
+            const newTableData = oldTableData.map((item) => {
+              if (item.id === table.id) {
+                return table;
+              }
+              return item;
+            });
+            setTableData([]);
+            setTableData(newTableData);
+          }
+        } else {
+          // 如果某个表格的行数据不存在
+          // 写入可编辑控件
+          table.value = rows;
+          // 写入不可编辑控件
+          table.value[rowIndex] = addUnEditableColumn(
+            table.value[rowIndex],
+            tableID,
+          );
+          const newTableData = oldTableData.map((item) => {
+            if (item.id === table.id) {
+              return table;
+            }
+            return item;
+          });
+          setTableData(newTableData);
+        }
+      } else {
+        // 如果某个table的数据不存在
+        rows[rowIndex] = addUnEditableColumn(rows[rowIndex], tableID);
+        const newTableData = [
+          {
+            name: tableLabel,
+            id: tableID,
+            type: tableID.split('_')[0],
+            value: rows,
+          },
+        ];
+        setTableData([...oldTableData, ...newTableData]);
+      }
+    } else {
+      // 如果没有数据
+      // 添加不可编辑控件
+      rows[rowIndex] = addUnEditableColumn(rows[rowIndex], tableID);
+      const newTableData = [
+        {
+          name: tableLabel,
+          id: tableID,
+          type: tableID.split('_')[0],
+          value: rows,
+        },
+      ];
+      setTableData(newTableData);
+    }
+  };
+
+  const addUnEditableColumn = (rows, tableID) => {
+    const { columns: originColumns } = data.formData.find(
+      (item) => item.props.id === tableID,
+    );
+    // 检查是否有文字说明控件,有的话需要添加在第几列的index后写入tableData
+    const allTextNote = originColumns.filter((item, index) => {
+      if (item.componentName === 'TextNote') {
+        item.index = index;
+        return true;
+      }
+      return false;
+    });
+    // 对这个表格的每个第 (allTextNote.item 的 index )列写入
+    let textNoteCellList = [];
+    if (allTextNote && allTextNote.length) {
+      textNoteCellList = allTextNote.map((item) => {
+        return {
+          name: item.props.label,
+          id: item.props.id,
+          type: item.componentName,
+          value: [item.props.placeholder],
+          colIndex: item.index,
+        };
+      });
+    }
+    if (textNoteCellList.length) {
+      for (const note of textNoteCellList) {
+        rows[note.colIndex] = note;
+      }
+    }
+    return rows;
+  };
+
+  const submit = async () => {
     form.validateFields().then((values) => {
       const { form: formCur } = formValueRef.current;
-      let audit_list = [],
-        cc_list = [];
+      let audit_list = [];
+      let cc_list = [];
       approvalProcess?.forEach((item, index) => {
-        let arr = item[0].is_cc == 1 ? cc_list : audit_list;
+        let arr = item[0].is_cc === 1 ? cc_list : audit_list;
 
-        if (item[0].type == 'role') arr.push(auditCheck[index]);
-        else if (item[0].type == 'leader')
+        if (item[0].type === 'role') arr.push(auditCheck[index]);
+        else if (item[0].type === 'leader')
           arr.push(
             ...leaderData.slice(0, item[0].value).map((leader) => leader.ID),
           );
         else arr.push(item.map((cur) => cur.value));
       });
-      let files = [],
-        formData = [];
+      let files = [];
+      let formData = [];
       formCur.forEach((item) => {
-        if (item.type == 'DDAttachment') {
+        if (item.type === 'DDAttachment') {
           files = files.concat(item.value);
         } else {
           formData.push(item);
         }
       });
-      console.log(audit_list, cc_list);
+
+      // 根据表格在原来的form中的顺序插入
+      const tableIndex = tableData.map((table) => {
+        return data.formData.findIndex((item) => item.props.id === table.id);
+      });
+
+      // 按保存的顺序把表格再插入进去
+      tableIndex.forEach((item, index) => {
+        formData.splice(item, 0, tableData[index]);
+      });
       createRun({
         flow_id: Number(oaId),
         form: JSON.stringify(formData),
@@ -147,9 +306,11 @@ const OaDetail = () => {
               />
             )} */}
           <AuditDetailed
+            allValues={formValueRef.current.form}
             form={form}
             items={data?.formData}
             onValuesChange={advanceSubmit}
+            onTableValChange={handleTableValChange}
           />
         </Col>
         <Col span={12}>

+ 53 - 9
src/pages/Flow/components/AuditDetailed.js

@@ -1,10 +1,26 @@
 import DDComponents from '@/components/DDComponents';
 import React, { useMemo, useState } from 'react';
 import { Button, Form } from 'antd';
+import { FormulaType } from '@/components/AuditForm/FormulaModal';
 
 const AuditDetailed = (props) => {
   // const [form] = Form.useForm();
-  const { items, form, onValuesChange } = props;
+  const {
+    allValues = [],
+    items,
+    form,
+    onValuesChange,
+    onTableValChange,
+  } = props;
+
+  const depId = useMemo(() => {
+    const id = items.find((item) => item.componentName == 'DepartmentField')
+      ?.props.id;
+    const value = allValues.find((item) => item.id == id)?.value;
+    if (value) return value[0];
+  }, [allValues, items]);
+
+  console.log(items, allValues);
   const data = useMemo(() => {
     let linkedData = {};
     items.forEach((d) => {
@@ -57,17 +73,45 @@ const AuditDetailed = (props) => {
       }
     }
 
+    const renderComponents = () => {
+      let content = '';
+      if (item.componentName === 'CodeField') {
+        content = <DDComponents item={item} depId={depId} />;
+      } else if (item.componentName === 'FormulaField') {
+        const strList = item.props?.formula?.map((formu) => {
+          if (formu.type == FormulaType.Filed) {
+            const numItem = allValues?.find((item) => item.id == formu.id);
+            return numItem?.value[0] || 0;
+          } else {
+            return formu.label;
+          }
+        });
+        console.log('-------44444-------------', item, strList);
+        const evalStr = strList?.join('');
+        content = <DDComponents item={item} evalStr={evalStr} />;
+      } else {
+        content = <DDComponents item={item} />;
+      }
+      return content;
+    };
+
     // const component = DDComponents({ item });
     // if (!component) return null;
     return (
-      <Form.Item
-        key={id}
-        name={id}
-        label={formLabel}
-        rules={[{ required: required }]}
-      >
-        <DDComponents item={item} />
-      </Form.Item>
+      <>
+        {item?.isTable === undefined ? (
+          <Form.Item
+            key={id}
+            name={id}
+            label={formLabel}
+            rules={[{ required: required }]}
+          >
+            {renderComponents()}
+          </Form.Item>
+        ) : (
+          <DDComponents item={item} onChange={onTableValChange} />
+        )}
+      </>
     );
   };
 

+ 25 - 11
src/pages/Flow/components/FormAndFilesNode.js

@@ -1,16 +1,17 @@
 import { Card, Col, Row, Empty } from 'antd';
-import { Form } from 'antd';
+import { Form, Table } from 'antd';
 import { useMemo, useState } from 'react';
 import { useModel } from 'umi';
 import AttachmentTable from '@/components/AttachmentTable';
 import InnerContactField from '@/components/DDComponents/InnerContactField';
 import DepartmentField from '@/components/DDComponents/DepartmentField';
 import ProjectField from '@/components/DDComponents/ProjectField';
+import DIYTable from '../../../components/DDComponents/DIYTable';
 
 const FormAndFilesNode = (props) => {
   const { formData, fileList } = props;
 
-  const renderFormItem = (type, value) => {
+  const renderFormItem = (type, value, item) => {
     switch (type) {
       case 'InnerContactField':
         return <InnerContactField value={value} disabled={true} />;
@@ -40,20 +41,33 @@ const FormAndFilesNode = (props) => {
     if (!data) return <Empty description="没有表单信息" />;
     try {
       const formData = JSON.parse(data);
-      if (formData.length == 0) return <Empty description="没有表单信息" />;
+      if (formData.length === 0) return <Empty description="没有表单信息" />;
       return (
         <>
           {formData.map((item, idx) => {
             const value = item.value.join(',');
             return (
-              <Form.Item
-                key={`FormAndFilesNode_${idx}`}
-                labelCol={{ span: 4 }}
-                wrapperCol={{ span: 14 }}
-                label={item.name}
-              >
-                {renderFormItem(item.type, value)}
-              </Form.Item>
+              <>
+                {item.type !== 'DIYTable' ? (
+                  <Form.Item
+                    key={`FormAndFilesNode_${idx}`}
+                    labelCol={{ span: 4 }}
+                    wrapperCol={{ span: 14 }}
+                    label={item.name}
+                    labelAlign="left"
+                  >
+                    {renderFormItem(item.type, value, item)}
+                  </Form.Item>
+                ) : (
+                  <div style={{ marginBottom: '24px' }}>
+                    <DIYTable
+                      table={item}
+                      columns={item.value}
+                      displayOnly={true}
+                    ></DIYTable>
+                  </div>
+                )}
+              </>
             );
           })}
         </>

+ 43 - 10
src/pages/Flow/index.js

@@ -11,14 +11,19 @@ import {
 
 function Audit(props) {
   const { list = [], classify = [], dispatch, loading } = props;
+
   let navigate = useNavigate();
+
   const [modal, contextHolder] = Modal.useModal();
+
   const [data, setData] = useState();
   const [visible, setVisible] = useState({
     audit: false,
     auditNode: false,
   });
+
   const detailRef = useRef();
+
   const columns = [
     {
       title: '审批流名称',
@@ -27,20 +32,24 @@ function Audit(props) {
     {
       title: '分类',
       dataIndex: 'classify_id',
-      render: (id) => classify?.find((item) => item.id == id)?.name || 'BOM',
+      render: (id) => classify?.find((item) => item.id === id)?.name || 'BOM',
     },
     {
       title: '操作',
       render: (item, index) => (
         <Space>
-          <a
+          <Button
+            size="small"
+            type="link"
             onClick={() => {
               setCurrentNode(item);
             }}
           >
             编辑
-          </a>
-          <a
+          </Button>
+          <Button
+            size="small"
+            type="link"
             onClick={() => {
               setData(item);
               changeVisible('audit', true);
@@ -48,12 +57,20 @@ function Audit(props) {
             }}
           >
             复制
-          </a>
-          <a onClick={() => handleDel(item)}>删除</a>
+          </Button>
+          <Button
+            size="small"
+            type="link"
+            danger
+            onClick={() => handleDel(item)}
+          >
+            删除
+          </Button>
         </Space>
       ),
     },
   ];
+
   const queryDetail = async (item) => {
     const res = await queryProcessFlows({ ids: Number(item.id) });
     if (res?.data) {
@@ -62,7 +79,7 @@ function Audit(props) {
   };
 
   const handleDel = (item) => {
-    console.log(item);
+    console.log(item.id);
     modal.confirm({
       title: '提示',
       content: `确定删除改审批流【${item.name}】删除后不能复原!`,
@@ -70,12 +87,12 @@ function Audit(props) {
         //删除审批流
         await queryFlowDelete(item.id)
           .then((data) => {
-            if (data?.code == 200) {
+            if (data?.code === 200) {
               message.success('删除成功');
               dispatch({
                 type: 'flow/queryAuditList',
                 payload: {
-                  flow_type: 1,
+                  flow_type: 'all',
                 },
               });
             }
@@ -106,6 +123,7 @@ function Audit(props) {
       },
     });
   };
+
   const handleAuditOk = (values) => {
     dispatch({
       type: 'flow/addAudit',
@@ -115,16 +133,24 @@ function Audit(props) {
       },
       callback: () => {
         message.success('新增成功');
+        dispatch({
+          type: 'flow/queryAuditList',
+          payload: {
+            flow_type: 'all',
+          },
+        });
         changeVisible('audit', false);
       },
     });
   };
+
   const changeVisible = (type, visible) => {
     setVisible({
       ...visible,
       [type]: visible,
     });
   };
+
   const setCurrentNode = (item) => {
     localStorage.setItem('currentAudit', JSON.stringify(item));
     dispatch({
@@ -164,11 +190,18 @@ function Audit(props) {
         新建流程
       </Button>
       <Table
-        style={{ marginTop: 20 }}
+        style={{ marginTop: 15, maxHeight: 'calc(100% - 120px)' }}
         loading={loading['flow/queryAuditList']}
         rowKey="id"
         dataSource={list}
         columns={columns}
+        pagination={{
+          position: ['bottomRight'],
+          total: list.length,
+          pageSize: 9,
+          responsive: true,
+          showSizeChanger: false,
+        }}
       />
 
       <AuditModal

+ 11 - 1
src/pages/Home/index.js

@@ -85,15 +85,25 @@ function HomePage(props) {
       },
       Icon: require('@/assets/UnityMenu/system.png'),
     },
+
     {
       id: 9,
       name: '个人中心',
       active: true,
       click: () => {
-        navigate('/profile/apply');
+        navigate('/profile');
       },
       Icon: require('@/assets/UnityMenu/userCenter.png'),
     },
+    {
+      id: 10,
+      name: 'cad管理',
+      active: true,
+      click: () => {
+        navigate('/cad');
+      },
+      Icon: require('@/assets/UnityMenu/cad.png'),
+    },
   ];
   return (
     <div className={menuStyle.background}>

+ 2 - 1
src/pages/ManufacturerMng/ManufacturerList.js

@@ -28,8 +28,9 @@ import {
 function ManufacturerList(props) {
   const { projectId = 1, data } = props;
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   const [visible, setVisible] = useState(false);
   const [curItem, setCurItem] = useState(null);
   const [formDisabled, setFormDisabled] = useState(false);

+ 14 - 2
src/pages/PSRManage/components/saveOtherModal.js

@@ -1,9 +1,11 @@
-import { DatePicker, Modal } from 'antd';
+import { DatePicker, Modal, Radio } from 'antd';
 import dayjs from 'dayjs';
 
 import { useState } from 'react';
 const SaveModal = ({ loading, open, onCancel, onOk }) => {
   const [date, setDate] = useState(dayjs());
+  const [tab, setTab] = useState('1');
+
   const onChange = (date, dateString) => {
     console.log(date, dateString);
     setDate(`${dateString}-01`);
@@ -16,7 +18,17 @@ const SaveModal = ({ loading, open, onCancel, onOk }) => {
       onCancel={onCancel}
       onOk={() => onOk(date)}
     >
-      <DatePicker date={date} picker="month" onChange={onChange} />
+      <span>类型:</span>
+      <Radio.Group onChange={(e) => setTab(e.target.value)} defaultValue={tab}>
+        <Radio.Button value="1">月版本</Radio.Button>
+        <Radio.Button value="2">基础版本</Radio.Button>
+      </Radio.Group>
+      {tab == '1' && (
+        <div style={{ marginTop: '20px' }}>
+          <span>月份:</span>
+          <DatePicker date={date} picker="month" onChange={onChange} />
+        </div>
+      )}
     </Modal>
   );
 };

+ 65 - 18
src/pages/PSRManage/detail.js

@@ -22,16 +22,18 @@ import SaveModal from './components/saveOtherModal';
 import CompareModal from './components/compareModal';
 import CompareCom from './components/compareCom';
 import dayjs from 'dayjs';
+import { getToken } from '@/utils/utils';
 import { exportExcel, getUUID } from '../../utils/exportExcl';
+import { stringify } from 'qs';
 const PSRDetail = () => {
   const navigate = useNavigate();
   const params = useParams();
   const location = useLocation();
+  const token = getToken();
   const { id: projectId } = params;
   const {
     state: { project_name, flow_id, node_id },
   } = location;
-  console.log('========================', location, luckysheet);
 
   const [excelData, setExcelData] = useState();
   const [historyOpen, setHistoryOpen] = useState();
@@ -79,15 +81,15 @@ const PSRDetail = () => {
   };
 
   //请求投标版、签字版psr excel
-  const { run: runExcel } = useRequest(queryPsrExcel, {
-    manual: true,
-    formatResult: (res) => {
-      if (res) {
-        const jsonData = JSON.parse(res);
-        renderSheet(jsonData);
-      }
-    },
-  });
+  // const { run: runExcel } = useRequest(queryPsrExcel, {
+  //   manual: true,
+  //   formatResult: (res) => {
+  //     if (res) {
+  //       const jsonData = JSON.parse(res);
+  //       renderSheet(jsonData);
+  //     }
+  //   },
+  // });
 
   //请求月度psr和现金流列表 data_type 1 psr 2 现金流
   const {
@@ -146,15 +148,31 @@ const PSRDetail = () => {
     if (key) {
       onChange(key);
     } else {
-      runExcel({ gridKey: node_id });
+      queryPsrExcel({ gridKey: node_id });
     }
   }, [key]);
+  //请求投标版、签字版psr excel
+  const queryPsrExcel = (data) => {
+    axios({
+      url: `/api/v1/purchase/record/sheet?${stringify(data)}`,
+      method: 'POST',
+      data,
+      headers: {
+        'JWT-TOKEN': token,
+      },
+    }).then((req) => {
+      if (req.status == 200) {
+        const jsonData = JSON.parse(req.data);
+        renderSheet(jsonData);
+      }
+    });
+  };
 
   const onChange = (key) => {
     if (key == '1') {
-      runExcel({ gridKey: node_id });
+      queryPsrExcel({ gridKey: node_id });
     } else if (key == '2') {
-      runExcel({ gridKey: flow_id });
+      queryPsrExcel({ gridKey: flow_id });
     } else {
       initPsrActrual(key);
     }
@@ -171,7 +189,7 @@ const PSRDetail = () => {
       setExcelData({ ...res.data[0], dayFormat: day });
       const data = JSON.parse(res.data[0].json_data);
       console.log(data);
-      if (data.cell_data) data.celldata = JSON.parse(data.cell_data);
+      if (data.celldata) data.celldata = JSON.parse(data.celldata);
       if (data.config) data.config = JSON.parse(data.config);
       renderSheet(
         Array.isArray(data) ? data : [data],
@@ -214,6 +232,13 @@ const PSRDetail = () => {
     luckysheetRef.current = contentWindow.luckysheet;
   };
   const renderSheet = (currentData, is_edit = false) => {
+    console.log('==================', luckysheetRef.current);
+    if (!luckysheetRef.current) {
+      setTimeout(() => {
+        renderSheet(currentData, is_edit);
+      }, 500);
+      return;
+    }
     const data = currentData;
     //设置单元格不可编辑
     data?.forEach((item) => {
@@ -250,7 +275,6 @@ const PSRDetail = () => {
     };
     option.data.forEach((item) => {
       delete item.data;
-      delete item.cell_data;
       if (item.celldata) {
         item.celldata.forEach((cell) => {
           // 生成uuid
@@ -294,6 +318,29 @@ const PSRDetail = () => {
           </Button>
         </div>
       );
+    if (data_type == 3)
+      return (
+        <div className={styles.excelTitle}>
+          <div>
+            当前PSR表单:
+            <span style={{ color: 'blue' }}>{excelData?.dayFormat}</span>
+          </div>
+          <Space>
+            <Button
+              type="primary"
+              onClick={() => {
+                runList();
+                setHistoryOpen(true);
+              }}
+            >
+              {`${title}历史版本`}
+            </Button>
+            <Button type="primary" onClick={() => exportExcl(title)}>
+              导出
+            </Button>
+          </Space>
+        </div>
+      );
     return (
       <div className={styles.excelTitle}>
         <div>
@@ -344,12 +391,12 @@ const PSRDetail = () => {
     {
       key: '2',
       label: '签字版PSR',
-      children: renderTitle(0, '签字版PSR'),
+      children: renderTitle(3, '签字版PSR'),
     },
     {
       key: '3',
-      label: '终版PSR',
-      children: renderTitle(1, '终版PSR'),
+      label: '过程/终版PSR',
+      children: renderTitle(1, '过程/终版PSR'),
     },
     {
       key: '4',

+ 2 - 1
src/pages/Profile/apply.js

@@ -33,8 +33,9 @@ const TYPE = {
 };
 function Apply(props) {
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   const [tabActive, setTabActive] = useState('1');
   const [detail, setDetail] = useState({});
   const [conVisible, setConVisible] = useState(false);

+ 16 - 41
src/pages/Profile/approve.js

@@ -34,9 +34,8 @@ const TYPE = {
   OA: 2,
 };
 function Approve(props) {
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { initialState } = useModel('@@initialState');
+  const user = initialState?.user || {};
   const [tabActive, setTabActive] = useState('1');
   const [detail, setDetail] = useState({});
   const [conVisible, setConVisible] = useState(false);
@@ -92,42 +91,19 @@ function Approve(props) {
     data: conAuditData,
     run: conAuditRun,
     loading: conAduitLoading,
-  } = useRequest((data) => queryGetContractList(data), {
-    // manual: true,
-    formatResult: contractResult,
-  });
-
-  // //审核合同
-  // const { run: runCheck, loading: checkLoading } = useRequest(
-  //   (data) => queryContractCheck(data),
-  //   {
-  //     manual: true,
-  //     onSuccess: () => {
-  //       conAuditRun({ multi_status: '1,4', current: 1, page_size: 10 });
-  //       // conAuditedRun({ check_by: user.CName });
-  //       setConVisible(false);
-  //       message.success('审核成功');
-  //     },
-  //     onErroe: () => {
-  //       message.error('审核失败');
-  //     },
-  //   },
-  // );
-  // //作废审核
-  // const { run: calCheckRun } = useRequest(
-  //   (data) => queryContractCancelCheck(data),
-  //   {
-  //     manual: true,
-  //     onSuccess: () => {
-  //       message.success('审核成功');
-  //       setConVisible(false);
-  //       conAuditRun({ multi_status: '1,4', current: 1, page_size: 10 });
-  //     },
-  //     onError: () => {
-  //       message.success('审核失败');
-  //     },
-  //   },
-  // );
+  } = useRequest(
+    (data) =>
+      queryGetContractList({
+        ...data,
+        is_parent: -1,
+        multi_status: '1,4',
+        page_size: 999,
+      }),
+    {
+      // manual: true,
+      formatResult: contractResult,
+    },
+  );
 
   //审核合同
   const { run: runOACheck } = useRequest(audit, {
@@ -145,7 +121,7 @@ function Approve(props) {
       setConVisible(false);
       message.success('审核成功');
     },
-    onErroe: () => {
+    onError: () => {
       message.error('审核失败');
     },
   });
@@ -307,7 +283,6 @@ function Approve(props) {
     if (activeKey == '1')
       return (
         <>
-          {' '}
           <Form
             name="basic"
             // labelCol={{ span: 0 }}

+ 2 - 1
src/pages/Profile/approved.js

@@ -25,7 +25,8 @@ const TYPE = {
   OA: 2,
 };
 function Approved(props) {
-  const { initialState: { user }  } = useModel('@@initialState');
+  const { initialState  } = useModel('@@initialState');
+  const user = initialState?.user || {}
   // const [tabActive, setTabActive] = useState('1');
   // const [detail, setDetail] = useState({});
   const [conVisible, setConVisible] = useState(false);

+ 230 - 394
src/pages/Profile/index.js

@@ -1,237 +1,53 @@
 import React, { Fragment, useState, useEffect, useMemo, useRef } from 'react';
 import { useNavigate } from 'umi';
 import {
-  Card,
   Table,
-  Empty,
-  Button,
   Modal,
-  message,
-  Form,
   DatePicker,
-  Row,
-  Col,
+  Divider,
+  Input,
+  Space,
+  Button,
   Select,
 } from 'antd';
-const { RangePicker } = DatePicker;
-import { useRequest, useModel } from '@umijs/max';
-import { queryProfileList, queryApplyList } from '@/services/boom';
+import { useModel, useRequest } from '@umijs/max';
+import { queryProfileList, queryApplyList, applyRepeal } from '@/services/boom';
 import dayjs from 'dayjs';
-import { queryContractCheck, queryGetContractList } from '@/services/contract';
-import ContractModal, {
-  Status,
-  StatusText,
-  Type,
-} from '../ContractManager/component/Modal';
 import PageContent from '@/components/PageContent';
+import { queryApprovedList } from '@/services/contract';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+
+export const Type = {
+  OA: 1,
+  CON: 2,
+};
 
 function profile(props) {
-  const {
-    initialState: { user },
-  } = useModel('@@initialState');
+  const { userList, run } = useModel('userList');
   const [tabActive, setTabActive] = useState('1');
-  const approveFormRef = useRef();
-  const applyFormRef = useRef();
-  let navigate = useNavigate();
-  const [detail, setDetail] = useState({});
-  const [conVisible, setConVisible] = useState(false);
-
-  const TYPE = {
-    Contract: 1,
-    OA: 2,
-  };
-
-  //OA我的申请列表
-  const {
-    data: OAApplyData,
-    run: OAApplyRun,
-    loading: OAApplyLoading,
-  } = useRequest(queryProfileList, {
-    // manual: true,
-    formatResult: (res) => {
-      return res.data?.list?.map((item) => {
-        return {
-          ...item,
-          CName: item.AuthorInfo.CName,
-          table_desc: [item.table_desc],
-          statusText: (() => {
-            switch (item.audit_status) {
-              case 0:
-                return '审核中';
-              case 1:
-                return '通过';
-              case 2:
-                return '拒绝';
-              case 3:
-                return '终审通过';
-            }
-          })(),
-          key: `${TYPE.Contract}_${item.id}`,
-          type: TYPE.OA,
-        };
-      });
-    },
-  });
-  //OA我的审批和待审批列表
-  const {
-    data: OAAuditData,
-    run: OAAuditRun,
-    loading: OAAuditLoading,
-  } = useRequest(queryProfileList, {
-    manual: true,
-    formatResult: (res) => {
-      return res.data?.list?.map((item) => {
-        return {
-          ...item,
-          CName: item.AuthorInfo.CName,
-          table_desc: [item.table_desc],
-          statusText: item.status,
-          // key: `${TYPE.Contract}_${item.id}`,
-          showBtn: true,
-          type: TYPE.OA,
-        };
-      });
-    },
-  });
-
-  //合同管理返回处理函数
-  const contractResult = (res) => {
-    let data = res.data?.list;
-    return data?.map((item) => {
-      return {
-        ...item,
-        table_name: `${user.CName}提交的合同审批`,
-        table_desc: [
-          `合同名称:${item.name}`,
-          `合同编号:${item.code}`,
-          `合同金额:${item.amount}万元`,
-        ],
-        CName: user.CName,
-        create_time: item.cancel_on || item.created_on,
-        type: TYPE.Contract,
-        statusText: StatusText[item.status],
-        showBtn:
-          item.status == Status.Checking || item.status == Status.CalChecking,
-        // key: `${TYPE.Contract}_${item.id}`,
-      };
-    });
-  };
-
-  //合同管理相关数据
-  //请求我的申请列表
-  const {
-    data: conApplyData,
-    run: conApplyRun,
-    loading: conApplyLoading,
-  } = useRequest(queryGetContractList, {
-    defaultParams: [{ created_by: user?.ID }],
-    formatResult: contractResult,
-  });
-  //我的待审批列表
-  const {
-    data: conAuditData,
-    run: conAuditRun,
-    loading: conAduitLoading,
-  } = useRequest((data) => queryGetContractList(data), {
-    manual: true,
-    formatResult: contractResult,
+  const [loading, setLoading] = useState(false);
+  const [columns, setColumes] = useState([]);
+  const [name, setName] = useState('');
+  const [data, setData] = useState({
+    list: [],
+    pagination: {},
   });
-  //我审批过的列表
-  const {
-    data: conAuditedData,
-    run: conAuditedRun,
-    loading: conAduitedLoading,
-  } = useRequest((data) => queryGetContractList(data), {
-    manual: true,
-    formatResult: contractResult,
-  });
-
-  //审核合同
-  const { run: runCheck, loading: checkLoading } = useRequest(
-    (data) => queryContractCheck(data),
-    {
-      manual: true,
-      onSuccess: () => {
-        conAuditRun({ status: 1 });
-        conAuditedRun({ check_by: user.CName });
-        setConVisible(false);
-        message.success('审核成功');
-      },
-      onErroe: () => {
-        message.error('审核失败');
-      },
-    },
-  );
-
-  //拼接审核数据和申请数据  审核loading和申请loading
-  const auditData = useMemo(() => {
-    let result = [];
-    if (OAAuditData && OAAuditData.length > 0) result = [...OAAuditData];
-    if (conAuditData && conAuditData.length > 0)
-      result = [...result, ...conAuditData];
-    if (conAuditedData && conAuditedData.length > 0)
-      result = [...result, ...conAuditedData];
-    return result;
-  }, [OAAuditData, conAuditData, conAuditedData]);
-
-  const auditLoading = useMemo(() => {
-    let loading = false;
-    if (OAAuditLoading || conAduitLoading || conAduitedLoading) loading = true;
-    return loading;
-  }, [OAAuditLoading, conAduitLoading, conAduitedLoading]);
-
-  const applyData = useMemo(() => {
-    let result = [];
-    if (OAApplyData && OAApplyData.length > 0) result = [...OAApplyData];
-    if (conApplyData && conApplyData.length > 0)
-      result = [...result, ...conApplyData];
-    return result;
-  }, [OAApplyData, conApplyData]);
-
-  const applyLoading = useMemo(() => {
-    let loading = false;
-    if (OAApplyLoading || conApplyLoading) loading = true;
-    return loading;
-  }, [OAApplyLoading, conApplyLoading]);
-
-  // useEffect(() => {
-  //   if (user?.Permission['menu-001-audit']) run({ status: 1 });
-  // }, [user]);
+  let navigate = useNavigate();
 
-  const onTabChange = (activeKey) => {
-    if (activeKey == '1') {
-      OAApplyRun();
-      conApplyRun();
-    } else {
-      OAAuditRun();
-      if (user?.Permission['menu-001-audit']) conAuditRun({ status: 1 });
-      conAuditedRun({ check_by: user.CName });
-    }
-    setTabActive(activeKey);
-  };
-  const columns = [
+  const columnsApplay = [
     {
       title: '标题',
-      dataIndex: 'table_name',
+      dataIndex: 'name',
       width: '30%',
     },
-    {
-      title: '摘要',
-      dataIndex: 'table_desc',
-      render: (descList) => {
-        return (
-          <ul>
-            {descList?.map((item) => (
-              <li>{item}</li>
-            ))}
-          </ul>
-        );
-      },
-    },
+
     {
       title: '发起人',
-      dataIndex: 'CName',
+      // dataIndex: 'CName',
       width: '20%',
+      render: (record) => (
+        <div>{record.CName ? record.CName : record.AuthorInfo?.CName}</div>
+      ),
     },
     {
       title: '发起时间',
@@ -242,203 +58,194 @@ function profile(props) {
     },
     {
       title: '流程状态',
-      dataIndex: 'statusText',
-      // render: (record) => {
-      //   switch (record.audit_status) {
-      //     case 0: return '审核中'
-      //     case 1: return '通过'
-      //     case 2: return '拒绝'
-      //     case 3: return '终审通过'
-      //   }
-      // },
-      // width: '20%'
+      // dataIndex: 'status',
+      render: (record) => {
+        if (record.is_repeal) return '已撤回';
+        switch (record.audit_status) {
+          case 0:
+            return '审核中';
+          case 1:
+            return '通过';
+          case 2:
+            return '拒绝';
+          case 3:
+            return '终审通过';
+        }
+      },
+      width: '20%',
     },
     {
       title: '操作',
-      render: (text, record) => (
-        <Fragment>
-          <>
-            <a
-              style={{ color: '#4096ff' }}
-              onClick={() => {
-                navigate(`/profile/${record.id}`);
-              }}
-            >
-              详情
-            </a>
-          </>
-        </Fragment>
-      ),
-      width: '10%',
-    },
-  ];
-  const approveColumns = [
-    {
-      title: '标题',
-      dataIndex: 'table_name',
-    },
-    {
-      title: '摘要',
-      dataIndex: 'table_desc',
-      render: (descList) => {
+      render: (record) => {
         return (
-          <ul>
-            {descList?.map((item) => (
-              <li>{item}</li>
-            ))}
-          </ul>
+          !record.is_repeal && (
+            <Fragment>
+              <>
+                <a
+                  style={{ color: '#4096ff' }}
+                  onClick={() => {
+                    if (record.extend_code) {
+                      navigate('/profile/detail', {
+                        state: {
+                          id: record.id,
+                          code: record.extend_code,
+                          type: Type.CON,
+                        },
+                      });
+                    } else {
+                      navigate('/profile/detail', {
+                        state: { id: record.id, type: Type.OA },
+                      });
+                    }
+                  }}
+                >
+                  详情
+                </a>
+                {tabActive == '1' && record?.audit_status == 0 && (
+                  <>
+                    <Divider type="vertical" />
+                    <a
+                      style={{ color: '#4096ff' }}
+                      onClick={() => onRepeal(record)}
+                    >
+                      撤回
+                    </a>
+                  </>
+                )}
+              </>
+            </Fragment>
+          )
         );
       },
+      width: '10%',
     },
+  ];
+  const columnsApproved = [
     {
-      title: '发起人',
-      dataIndex: 'CName',
+      title: '标题',
+      dataIndex: 'name',
+      width: '30%',
     },
     {
       title: '发起时间',
       render: (record) => {
         return dayjs(record.create_time).format('YYYY-MM-DD HH:mm:ss');
       },
+      width: '20%',
     },
     {
-      title: '流程状态',
-      dataIndex: 'statusText',
+      title: '我审批的时间',
+      render: (record) => {
+        return dayjs(record.audit_time).format('YYYY-MM-DD HH:mm:ss');
+      },
+      width: '20%',
     },
     {
-      title: '操作',
-      dataIndex: 'showBtn',
-      render: (text, record) => (
-        <>
-          {text ? (
-            <a
-              style={{ color: '#4096ff' }}
-              onClick={() => {
-                if (record.type == TYPE.Contract) {
-                  setDetail(record);
-                  setConVisible(true);
-                } else {
-                  navigate(`/oa/detail/${record.flow_id}/${record.id}`);
-                }
-              }}
-            >
-              审批
-            </a>
-          ) : (
-            <div>已审批</div>
-          )}
-        </>
-      ),
+      title: '状态',
+      // dataIndex: 'status',
+      render: (record) => {
+        switch (record.audit_status) {
+          case 0:
+            return '审核中';
+          case 1:
+            return '通过';
+          case 2:
+            return '拒绝';
+          case 3:
+            return '终审通过';
+        }
+      },
+      width: '20%',
     },
   ];
-  const handleApplySubmit = (values) => {
-    console.log(values);
-    queryApplyListRequest.run(values);
+
+  //我的申请
+  const queryApplay = async (params) => {
+    const data = await queryApplyList(params);
+    console.log(data);
+    setData(data);
+    setLoading(false);
   };
-  const handleApproveSubmit = (values) => {
-    console.log(values);
+  //我的待审批
+  const queryApprove = async (params) => {
+    const data = await queryProfileList(params);
+    console.log(data);
+    setData(data);
+    setLoading(false);
   };
-  const handleApplyPaginationChange = (pagination) => {
-    queryApplyListRequest.run({
-      currentPage: pagination.current,
-      pageSize: pagination.pageSize,
-    });
+  //我的已审批
+  const queryApproved = async (params) => {
+    const data = await queryApprovedList(params);
+    console.log(data);
+    setData(data);
+    setLoading(false);
   };
-  const handleProfilePaginationChange = (pagination) => {
-    queryProfileListRequest.run({
-      currentPage: pagination.current,
-      pageSize: pagination.pageSize,
+
+  //撤回申请
+  const { run: runRepeal, loading: repealLoading } = useRequest(
+    (id) => applyRepeal({ id }),
+    {
+      manual: true,
+      onSuccess: () => {
+        handlerTabChange(tabActive);
+      },
+    },
+  );
+
+  const handlerTabChange = (tab) => {
+    setLoading(true);
+    if (name) setName('');
+    switch (tab) {
+      case '1':
+        setColumes(columnsApplay);
+        queryApplay();
+        break;
+      case '2':
+        setColumes(columnsApplay);
+        queryApprove();
+        break;
+      case '3':
+        setColumes(columnsApproved);
+        queryApproved();
+        break;
+    }
+  };
+
+  useEffect(() => {
+    run();
+    handlerTabChange('1');
+  }, []);
+
+  useEffect(() => {
+    handlerTabChange(tabActive);
+  }, [tabActive]);
+
+  const onRepeal = (record) => {
+    Modal.confirm({
+      title: '撤回',
+      icon: <ExclamationCircleOutlined />,
+      content: `确定撤回申请`,
+      okText: '确认',
+      cancelText: '取消',
+      onOk: () => {
+        runRepeal(record.id);
+      },
     });
   };
-  const renderPage = (activeKey) => {
-    if (activeKey == '1')
-      return (
-        <>
-          {' '}
-          <Form
-            name="basic"
-            // labelCol={{ span: 0 }}
-            // wrapperCol={{ span: 24 }}
-            onFinish={handleApplySubmit}
-            ref={applyFormRef}
-          >
-            <div style={{ display: 'flex' }}>
-              <Form.Item name="range-picker" label="申请时间:">
-                <RangePicker />
-              </Form.Item>
-              <Form.Item>
-                <Button
-                  type="primary"
-                  htmlType="submit"
-                  style={{ marginLeft: 10 }}
-                >
-                  查询
-                </Button>
-              </Form.Item>
-            </div>
-          </Form>
-          <Table
-            columns={columns}
-            dataSource={applyData}
-            loading={applyLoading}
-            // columns={columns}
-            // loading={queryApplyListRequest.loading}
-            // dataSource={queryApplyListRequest?.data?.list}
-            // pagination={queryApplyListRequest?.data?.pagination}
-            // onChange={handleApplyPaginationChange}
-          />
-        </>
-      );
-    else if (activeKey == '2')
-      return (
-        <>
-          {' '}
-          <Form
-            name="basic"
-            // labelCol={{ span: 0 }}
-            // wrapperCol={{ span: 24 }}
-            onFinish={handleApproveSubmit}
-            ref={approveFormRef}
-          >
-            <div style={{ display: 'flex' }}>
-              <Form.Item name="range-picker" label="审批时间:">
-                <RangePicker />
-              </Form.Item>
-              <Form.Item name="audit_status" label="状态:" initialValue="">
-                <Select
-                  style={{ width: 120 }}
-                  options={[
-                    { value: '', label: '全部' },
-                    { value: '0', label: '审核中' },
-                    { value: '1', label: '通过' },
-                    { value: '2', label: '拒绝' },
-                    { value: '3', label: '终审通过' },
-                  ]}
-                />
-              </Form.Item>
-              <Form.Item>
-                <Button
-                  type="primary"
-                  htmlType="submit"
-                  style={{ marginLeft: 10 }}
-                >
-                  查询
-                </Button>
-              </Form.Item>
-            </div>
-          </Form>
-          <Table
-            columns={approveColumns}
-            dataSource={auditData}
-            loading={auditLoading}
-            // loading={queryProfileListRequest.loading}
-            // columns={approveColumns}
-            // dataSource={queryProfileListRequest?.data?.list}
-            // pagination={queryProfileListRequest?.data?.pagination}
-            // onChange={handleProfilePaginationChange}
-          />
-        </>
-      );
+  const handleProfilePaginationChange = (pagination) => {
+    switch (tabActive) {
+      case '1':
+        queryApplay({ currentPage: pagination.current, pageSize: 10 });
+        break;
+      case '2':
+        queryApprove({ currentPage: pagination.current, pageSize: 10 });
+        break;
+      case '3':
+        queryApproved({ currentPage: pagination.current, pageSize: 10 });
+        break;
+    }
   };
+
   return (
     <PageContent
       tabList={[
@@ -450,19 +257,48 @@ function profile(props) {
           tab: '我的审批',
           key: '2',
         },
+        {
+          tab: '已审批',
+          key: '3',
+        },
       ]}
-      onTabChange={onTabChange}
+      onTabChange={setTabActive}
     >
-      <div>{renderPage(tabActive)}</div>
-      <ContractModal
-        detail={detail}
-        type={Type.check}
-        // projectList={projectData?.list}
-        visible={conVisible}
-        handleOk={(data) =>
-          detail.status == Status.Checking ? runCheck(data) : null
-        }
-        handleCancel={() => setConVisible(false)}
+      {tabActive == '2' && (
+        <Space style={{ marginBottom: '10px' }}>
+          <Select
+            value={name}
+            style={{ width: 300 }}
+            allowClear
+            showSearch
+            placeholder="发起人"
+            options={userList?.map((item) => {
+              return { value: item.ID, label: item.CName };
+            })}
+            onChange={(value) => setName(value)}
+            filterOption={(input, option) =>
+              (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
+            }
+          />
+          <Button
+            type="primary"
+            onClick={() =>
+              queryApprove({
+                pageSize: 10,
+                initiator: name,
+              })
+            }
+          >
+            查询
+          </Button>
+        </Space>
+      )}
+      <Table
+        columns={columns}
+        dataSource={data?.list}
+        loading={loading}
+        pagination={{ ...data?.pagination, showSizeChanger: false }}
+        onChange={handleProfilePaginationChange}
       />
     </PageContent>
   );

+ 2 - 1
src/pages/UserCenter/index.js

@@ -5,8 +5,9 @@ import { useState } from 'react';
 
 const ChangePassWord = () => {
   const {
-    initialState: { user },
+    initialState,
   } = useModel('@@initialState');
+  const user = initialState?.user || {}
   const navigate = useNavigate();
 
   const onFinish = async (values) => {

+ 5 - 2
src/services/approval.js

@@ -1,4 +1,4 @@
-import {request }from 'umi';
+import { request } from 'umi';
 import { stringify } from 'qs';
 
 //获取部门结构
@@ -6,6 +6,10 @@ export async function queryDepV2(params) {
   return request(`/api/v2/dep?${stringify(params)}`);
 }
 
+// 选择公司为本部时获取部门使用这个接口
+export async function queryDepsV2(params) {
+  return request(`/api/v2/main/deps`);
+}
 // export async function queryType() {
 //   return request(`/api/v2/approval/type/dic`);
 // }
@@ -67,7 +71,6 @@ export async function queryDepV2(params) {
 //   });
 // }
 
-
 // //添加项目成员
 // export async function addMember(data) {
 //   return request(`/api/v2/project_code/user`, {

+ 7 - 14
src/services/boom.js

@@ -217,22 +217,15 @@ export async function advanceSubmitNextNode(params) {
 
 export async function queryProfileList(params) {
   let profileList = await request(`/api/v1/oa/audit/list`, { params });
-  let auditList = await request(`/api/v1/purchase/flow/info?flow_type=1`);
-  profileList?.data?.list.map((item) => {
-    var audit = auditList?.data?.find(
-      (child) => item.flow_id === child?.list.id,
-    );
-    if (audit) {
-      item.table_name = item.AuthorInfo?.CName + audit.list.name;
-      item.table_desc = audit.list.desc;
-      item.status = '待审批';
-    }
-  });
-  console.log(profileList);
-  return profileList;
+  return profileList?.data;
 }
 export async function queryApplyList(params) {
-  return request(`/api/v1/oa/audit/my/list`, { params });
+  const res = await request(`/api/v1/oa/audit/my/list`, { params });
+  if (res?.data) {
+    return { list: res.data?.list, pagination: res.data?.pagination };
+  } else {
+    return { list: [], pagination: {} };
+  }
 }
 
 //获取多级主管

+ 10 - 0
src/services/cad.js

@@ -0,0 +1,10 @@
+import { request } from 'umi';
+export const queryCadList = async () => {
+  return await request('/api/contract/v1/cad');
+};
+export async function queryCreateCad(data) {
+  return request(`/api/contract/v1/cad`, {
+    method: 'POST',
+    data,
+  });
+}

+ 30 - 1
src/services/contract.js

@@ -63,9 +63,10 @@ export const queryContractCancelCheck = async (data) => {
 
 //OA已审核过的
 export const queryApprovedList = async (data) => {
-  return await request('/api/v1/oa/audited/my/list', {
+  const res = await request('/api/v1/oa/audited/my/list', {
     params: data,
   });
+  if (res?.data) return res.data;
 };
 
 //公司列表
@@ -98,3 +99,31 @@ export const queryDelById = async (data) => {
     params: data,
   });
 };
+
+//合同详情接口
+export const queryContractDetail = async (data) => {
+  return await request(`/api/contract/v1/detail`, {
+    params: data,
+  });
+};
+
+//保存草稿
+export const queryContractSaveDraft = async (data) => {
+  return await request('/api/contract/v1/draft', {
+    method: 'POST',
+    data,
+  });
+};
+//删除草稿?id=1
+export const queryDelDraft = async (data) => {
+  return await request(`/api/contract/v1/draft`, {
+    method: 'DELETE',
+    params: data,
+  });
+};
+//草稿列表/api/contract/v1/draft
+export const queryContractDraft = async (data) => {
+  return await request(`/api/contract/v1/draft`, {
+    params: data,
+  });
+};

Некоторые файлы не были показаны из-за большого количества измененных файлов