xujunjie před 2 roky
rodič
revize
76153047c0

+ 13 - 12
config/config.js

@@ -29,20 +29,20 @@ const plugins = [
       },
       pwa: pwa
         ? {
-          workboxPluginMode: 'InjectManifest',
-          workboxOptions: {
-            importWorkboxFrom: 'local',
-          },
-        }
+            workboxPluginMode: 'InjectManifest',
+            workboxOptions: {
+              importWorkboxFrom: 'local',
+            },
+          }
         : {},
       ...(!TEST && os.platform() === 'darwin'
         ? {
-          dll: {
-            include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
-            exclude: ['@babel/runtime'],
-          },
-          hardSource: false,
-        }
+            dll: {
+              include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
+              exclude: ['@babel/runtime'],
+            },
+            hardSource: false,
+          }
         : {}),
     },
   ],
@@ -140,7 +140,8 @@ export default {
   chainWebpack: webpackPlugin,
   proxy: {
     '/api': {
-      target: 'http://47.96.12.136:8896/',
+      target: 'http://192.168.20.152:8888/',
+      // target: 'http://47.96.12.136:8896/',
       // target: 'http://oraysmart.com:8889/',
       // target: 'http://oraysmart.com:8888/api',
       // changeOrigin: true,

+ 5 - 4
public/luckysheet.html

@@ -8,20 +8,21 @@
   <title>Document</title>
 
   <!-- 线上发布使用路径 -->
-  <link rel="stylesheet" href="/bom/Luckysheet/plugins/css/pluginsCss.css" />
+  <!-- <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>
+  <script src="/bom/Luckysheet/luckysheet.umd.js"></script> -->
 
   <!-- 本地开发使用路径 -->
-  <!-- <link rel='stylesheet' href='http://localhost:3000/plugins/css/pluginsCss.css' />
+
+  <link rel='stylesheet' href='http://localhost:3000/plugins/css/pluginsCss.css' />
   <link rel='stylesheet' href='http://localhost:3000/plugins/plugins.css' />
   <link rel='stylesheet' href='http://localhost:3000/css/luckysheet.css' />
   <link rel='stylesheet' href='http://localhost:3000/assets/iconfont/iconfont.css' />
   <script src="http://localhost:3000/plugins/js/plugin.js"></script>
-  <script src="http://localhost:3000/luckysheet.umd.js"></script> -->
+  <script src="http://localhost:3000/luckysheet.umd.js"></script>
 </head>
 
 <body>

+ 34 - 0
src/components/DDComponents/DDMultiSelectField/index.js

@@ -0,0 +1,34 @@
+import React from 'react';
+import { Select } from 'antd';
+
+const { Option } = Select;
+
+function DDSelectField(props) {
+  const { options, disabled, onChange } = props;
+
+  return (
+    <Select
+      mode="multiple"
+      allowClear
+      style={{ width: '100%' }}
+      disabled={disabled}
+      onChange={value => {
+        onChange(JSON.stringify(value));
+      }}
+    >
+      {options?.map(cur => {
+        if (typeof cur == 'string') {
+          cur = JSON.parse(cur);
+        }
+
+        return (
+          <Option key={cur.key} value={cur.value}>
+            {cur.value}
+          </Option>
+        );
+      })}
+    </Select>
+  );
+}
+
+export default DDSelectField;

+ 107 - 0
src/components/DDComponents/DDPhotoField/AliyunOssUploader.js

@@ -0,0 +1,107 @@
+import React from 'react'
+import { Upload, message, Button} from 'antd';
+import { PlusOutlined } from '@ant-design/icons';
+
+class AliyunOSSUpload extends React.Component {
+  state = {
+    OSSData: {},
+  };
+
+  componentDidMount() {
+    this.init();
+  }
+
+  init = () => {
+    try {
+      const { OSSData } = this.props;
+
+      this.setState({
+        OSSData,
+      });
+    } catch (error) {
+      message.error(error);
+    }
+  };
+
+  onChange = ({ file, fileList }) => {
+    const { onChange, onDone , onUploading} = this.props;
+    console.log('Aliyun OSS:', file, fileList);
+    if (onChange) {
+      onChange([...fileList]);
+    }
+
+    if (onDone) {
+      if (file.status === 'done')
+        onDone(file)
+    }
+    if(onUploading && file.status === 'uploading') {
+      onUploading({ file, fileList })
+    }
+    this.setState({ fileList: [...fileList] });
+  };
+
+  onRemove = file => {
+    const { value, onChange } = this.props;
+
+    const files = value.filter(v => v.url !== file.url);
+
+    if (onChange) {
+      onChange(files);
+    }
+  };
+
+  transformFile = file => {
+    const { OSSData } = this.state;
+    file.url = OSSData.dir + file.name;
+    return file;
+  };
+
+  getExtraData = file => {
+    const { OSSData } = this.state;
+
+    return {
+      key: file.url,
+      OSSAccessKeyId: OSSData.accessid,
+      policy: OSSData.policy,
+      Signature: OSSData.signature,
+    };
+  };
+
+  beforeUpload = async () => {
+    const { OSSData } = this.state;
+    const expire = OSSData.expire * 1000;
+
+    if (expire < Date.now()) {
+      await this.init();
+    }
+    return true;
+  };
+
+  render() {
+    const { value, directory, label, noStyle, showUploadList, accept } = this.props;
+    const props = {
+      name: 'file',
+      fileList: this.state.fileList,
+      action: this.state.OSSData.host,
+      onChange: this.onChange,
+      onRemove: this.onRemove,
+      transformFile: this.transformFile,
+      data: this.getExtraData,
+      beforeUpload: this.beforeUpload,
+      accept: accept,
+      showUploadList: showUploadList !== false,
+      headers: { "Access-Control-Allow-Origin": "*" }
+    };
+    return (
+      <Upload {...props} directory={directory}>
+        {noStyle ? label : (<Button type="primary">
+          <PlusOutlined /> {label}
+        </Button>)}
+
+      </Upload>
+    );
+  }
+}
+
+
+export default AliyunOSSUpload;

+ 46 - 0
src/components/DDComponents/DDPhotoField/index.js

@@ -0,0 +1,46 @@
+import React, { useState, useEffect } from 'react';
+import { Upload, Button, Image } from 'antd';
+import AliyunOssUploader from '@/components/OssUpload/AliyunOssUploader';
+import { queryOSSData } from '@/services/boom';
+
+function DDPhotoField(props) {
+  const { disabled, onChange } = props;
+  const [value, setValue] = useState([]);
+  const [ossData, setOssData] = useState();
+
+  const OnModelFileDone = file => {
+    var path = ossData.host + '/' + file.url;
+    let newValue = [...value, path];
+    setValue(newValue);
+    onChange(JSON.stringify(newValue));
+  };
+  const OnUploading = file => {};
+
+  useEffect(() => {
+    queryOSSData().then(res => {
+      setOssData(res.data);
+    });
+  }, []);
+
+  return ossData ? (
+    <div>
+      <div>
+        {value.map(img => (
+          <Image height={200} src={img} />
+        ))}
+      </div>
+      <AliyunOssUploader
+        OSSData={ossData}
+        onDone={OnModelFileDone}
+        onUploading={OnUploading}
+        noStyle={false}
+        showUploadList={false}
+        directory={false}
+        accept={'.png, .jpg, .jpeg'}
+        label="上传图片"
+      ></AliyunOssUploader>
+    </div>
+  ) : null;
+}
+
+export default DDPhotoField;

+ 60 - 0
src/components/DDComponents/DepartmentField/index.js

@@ -0,0 +1,60 @@
+import { TreeSelect } from 'antd';
+import React, { useState, useEffect } from 'react';
+import { queryDDdepList } from '@/services/boom';
+
+function DepartmentField(props) {
+  const { value, onChange } = props;
+
+  // const [value, setValue] = useState();
+  const [treeData, setTreeData] = useState([]);
+
+  const genTreeNode = dep => {
+    return {
+      id: dep.dept_id,
+      pId: dep.parent_id,
+      value: dep.dept_id,
+      title: dep.name,
+      isLeaf: false,
+    };
+  };
+
+  const onLoadData = async ({ id }) => {
+    let depList = await queryDDdepList({ dept_id: id });
+
+    console.log(depList);
+    if (depList.length > 0) {
+      let nodes = depList.map(genTreeNode);
+      setTreeData([...treeData, ...nodes]);
+    }
+  };
+
+  const onChangeValue = newValue => {
+    console.log(newValue);
+    let dep = treeData.find(dep => dep.id == newValue);
+    onChange({ value: dep?.title, extValue: JSON.stringify([{ name: dep?.title }]) });
+  };
+
+  useEffect(() => {
+    onLoadData({});
+  }, []);
+
+  return (
+    <TreeSelect
+      treeDataSimpleMode
+      style={{
+        width: '100%',
+      }}
+      // value={value}
+      dropdownStyle={{
+        maxHeight: 400,
+        overflow: 'auto',
+      }}
+      placeholder="请选择部门"
+      onChange={onChangeValue}
+      loadData={onLoadData}
+      treeData={treeData}
+    />
+  );
+}
+
+export default DepartmentField;

+ 29 - 0
src/components/DDComponents/InnerContactField/index.js

@@ -0,0 +1,29 @@
+import React from 'react';
+import { Select } from 'antd';
+import { connect } from 'dva';
+
+const { Option } = Select;
+
+function InnerContactField(props) {
+  const { userList, onChange } = props;
+
+  return (
+    <Select
+      showSearch
+      onChange={value => {
+        onChange(JSON.stringify([value]));
+      }}
+      filterOption={(input, option) => option.children.toLowerCase().includes(input.toLowerCase())}
+    >
+      {userList.map(item => (
+        <Option key={item.ID} value={item.DingUserId}>
+          {item.CName}
+        </Option>
+      ))}
+    </Select>
+  );
+}
+
+export default connect(({ user }) => ({
+  userList: user.list,
+}))(InnerContactField);

+ 18 - 0
src/components/DDComponents/NumberField/index.js

@@ -0,0 +1,18 @@
+import React from 'react';
+import { InputNumber } from 'antd';
+
+function NumberField(props) {
+  const { onChange,disabled, unit } = props;
+
+  return (
+    <InputNumber
+      disabled={disabled}
+      formatter={value => `${value}${unit || ''}`}
+      onChange={e => {
+        onChange?.(String(e));
+      }}
+    />
+  );
+}
+
+export default NumberField;

+ 19 - 0
src/components/DDComponents/PhoneField/index.js

@@ -0,0 +1,19 @@
+import React from 'react';
+import { Input, Row, Col, Select } from 'antd';
+import { connect } from 'dva';
+
+const { Option } = Select;
+
+function PhoneField(props) {
+  const { onChange } = props;
+  return (
+    <Input.Group size="large">
+      <Select defaultValue="+86">
+        <Option value="+86">+86</Option>
+      </Select>
+      <Input style={{ width: '80%' }} {...props} onChange={e => onChange(e.target.value)} />
+    </Input.Group>
+  );
+}
+
+export default PhoneField;

+ 79 - 0
src/components/DDComponents/TableField/index.js

@@ -0,0 +1,79 @@
+import { Button } from 'antd';
+import React, { useMemo } from 'react';
+import DDComponents from '../index';
+import style from './index.less';
+
+function TableField(props) {
+  const { item, value, onChange } = props;
+
+  const getEmptyValue = () => {
+    return item.children.map(children => ({
+      name: children.props.id,
+      value: '',
+    }));
+  };
+  const getChildren = (item, data) => {
+    let cur = data.find(d => d.name == item.props.id);
+    const childrenChange = value => {
+      cur.value = value;
+      onChange(JSON.stringify(localValue));
+    };
+    return DDComponents({ item, onChange: childrenChange, value: cur.value });
+  };
+
+  const localValue = useMemo(() => {
+    let v = [];
+    try {
+      v = JSON.parse(value);
+    } catch (error) {}
+    if (v.length == 0) {
+      let data = getEmptyValue();
+      v.push(data);
+    }
+    return v;
+  }, [value]);
+
+  const addRow = () => {
+    let newValue = [...localValue, getEmptyValue()];
+
+    onChange(JSON.stringify(newValue));
+  };
+
+  const removeRow = index => {
+    let newValue = [...localValue];
+    newValue.splice(index, 1);
+
+    onChange(JSON.stringify(newValue));
+  };
+
+  return (
+    <div>
+      <table className={style.table}>
+        <tr>
+          <th></th>
+          {item.children.map(item => (
+            <th>{item.props.label}</th>
+          ))}
+          <th>操作</th>
+        </tr>
+        {localValue.map((curItem, index) => (
+          <tr>
+            <td>{index + 1}</td>
+            {item.children.map(item => (
+              <td>{getChildren(item, curItem)}</td>
+            ))}
+            <td>
+              {localValue.length > 1 && <a onClick={() => removeRow(index)}>删除</a>}
+              {/* <a>复制</a> */}
+            </td>
+          </tr>
+        ))}
+      </table>
+      <Button style={{ marginTop: 20 }} onClick={addRow}>
+        {item.props.actionName}
+      </Button>
+    </div>
+  );
+}
+
+export default TableField;

+ 16 - 0
src/components/DDComponents/TableField/index.less

@@ -0,0 +1,16 @@
+.table {
+  width: 100%;
+  td {
+    padding: 10px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+  }
+  th {
+    padding: 10px;
+    color: #000000d9;
+    font-weight: 500;
+    text-align: left;
+    background: #fafafa;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+    transition: background 0.3s ease;
+  }
+}

+ 121 - 0
src/components/DDComponents/index.js

@@ -0,0 +1,121 @@
+import { Input, InputNumber, Select, DatePicker, Rate } from 'antd';
+import TableField from './TableField';
+import PhoneField from './PhoneField';
+import InnerContactField from './InnerContactField';
+import DepartmentField from './DepartmentField';
+import DDMultiSelectField from './DDMultiSelectField';
+import NumberField from './NumberField';
+import DDPhotoField from './DDPhotoField';
+
+const { Option } = Select;
+const { RangePicker } = DatePicker;
+
+export default function DDComponents(props) {
+  const { item, onChange } = props;
+  const {
+    id,
+    label,
+    bizAlias,
+    required,
+    placeholder,
+    options,
+    align,
+    statField,
+    hideLabel,
+    objOptions,
+    format,
+    pushToAttendance,
+    labelEditableFreeze,
+    requiredEditableFreeze,
+    unit,
+    extract,
+    link,
+    payEnable,
+    bizType,
+    childFieldVisible,
+    notPrint,
+    verticalPrint,
+    hiddenInApprovalDetail,
+    disabled,
+    notUpper,
+    children, // 子控件
+  } = item.props;
+  let component = null;
+  switch (item.componentName) {
+    case 'TextField': //单行输入
+      component = <Input disabled={disabled} placeholder={placeholder} onChange={onChange} />;
+      break;
+    case 'TextareaField': //多行输入
+      component = (
+        <Input.TextArea disabled={disabled} placeholder={placeholder} onChange={onChange} />
+      );
+      break;
+    case 'NumberField': //数字输入
+      component = <NumberField disabled={disabled} unit={unit} />;
+      break;
+    case 'DDSelectField': //单选框
+      component = (
+        <Select style={{ width: '100%' }} onChange={onChange}>
+          {options?.map(cur => {
+            if (typeof cur == 'string') {
+              cur = JSON.parse(cur);
+            }
+
+            return (
+              <Option key={cur.key} value={cur.value}>
+                {cur.value}
+              </Option>
+            );
+          })}
+        </Select>
+      );
+      break;
+    case 'DDMultiSelectField': //多选框
+      component = <DDMultiSelectField disabled={disabled} options={options} />;
+      break;
+    case 'DDDateField': //日期控件
+      component = <DatePicker format={format} onChange={onChange} />;
+      break;
+    case 'DDDateRangeField': //时间区间控件
+      component = <RangePicker format={format} onChange={onChange} />;
+      break;
+    case 'TextNote': //文本说明控件
+      // component = <p style={{textAlign: align}}></p>
+      break;
+    case 'PhoneField': //电话控件
+      component = <PhoneField onChange={onChange} />;
+      break;
+    case 'DDPhotoField': //图片控件
+      component = <DDPhotoField />;
+      break;
+    case 'MoneyField': //金额控件
+      component = <Input placeholder={placeholder} onChange={onChange} />;
+      break;
+    case 'TableField': //明细控件
+      component = <TableField item={item} />;
+      break;
+    case 'DDAttachment': //附件
+      // component = (
+      //   <Upload>
+      //     <Button icon={<PlusOutlined />}>添加附件</Button>
+      //   </Upload>
+      // );
+      break;
+    case 'InnerContactField': //联系人控件
+      component = <InnerContactField onChange={onChange}></InnerContactField>;
+      break;
+    case 'DepartmentField': //部门控件
+      component = <DepartmentField />;
+      break;
+    case 'RelateField': //关联审批单
+      break;
+    case 'AddressField': //省市区控件
+      break;
+    case 'StarRatingField': //评分控件
+      break;
+    case 'FormRelateField': //关联控件
+      break;
+  }
+
+  return component;
+}

+ 33 - 1
src/components/Flow/node/circle/mapServe.tsx

@@ -19,10 +19,41 @@ export interface IConfig {
   stroke?: string;
   flow_id?: string;
   flow_node_id?: string;
+  process_code?: string;
 }
 
 const Component = (props: any) => {
-  const { config, plugin = {}, auditList } = props;
+  // const auditList = [
+  //   {
+  //     icon_url: 'https://gw.alicdn.com/tfs/TB13f_aCQzoK1RjSZFlXXai4VXa-102-102.png',
+  //     is_new_process: false,
+  //     process_code: 'PROC-EF6YLU2SO2-TFNDPQR6RMN2002KUULI2-B7P8DLSI-V4',
+  //     gmt_modified: '2021-01-27 21:39:23',
+  //     flow_title: '财务证照及合同借用',
+  //     icon_name: 'tag',
+  //     attendance_type: 0,
+  //   },
+  //   {
+  //     icon_url: 'https://gw.alicdn.com/tfs/TB1KMniCNYaK1RjSZFnXXa80pXa-102-102.png',
+  //     is_new_process: false,
+  //     process_code: 'PROC-MOEKBM6V-GSAR5LHCTQYYP1BCEWCL1-GK9VAQBJ-5',
+  //     gmt_modified: '2021-03-05 10:28:06',
+  //     flow_title: '外部打印申请单',
+  //     icon_name: 'general_log',
+  //     attendance_type: 0,
+  //   },
+  //   {
+  //     icon_url: 'https://gw.alicdn.com/tfs/TB1KMniCNYaK1RjSZFnXXa80pXa-102-102.png',
+  //     is_new_process: false,
+  //     process_code: 'PROC-6B508B53-83F5-484C-8052-2FCA4FB57110',
+  //     gmt_modified: '2021-03-05 10:28:06',
+  //     flow_title: '组织架构调整',
+  //     icon_name: 'general_log',
+  //     attendance_type: 0,
+  //   },
+  // ];
+  const { config, plugin = {}, auditList } = props; //, auditList
+  console.log(auditList);
   const { updateNode } = plugin;
   const [nodeConfig, setNodeConfig] = useState<IConfig>({
     ...config,
@@ -79,6 +110,7 @@ const Component = (props: any) => {
             onNodeConfigChange(null, {
               flow_node_id: audit.list.FlowNodes[0]?.id,
               flow_id: value,
+              process_code: audit.list.process_code,
             });
           }}
           options={auditList.map(item => {

+ 103 - 0
src/pages/PurchaseAdmin/PurchaseList/Detail/AuditDetailed.js

@@ -0,0 +1,103 @@
+import DDComponents from '@/components/DDComponents';
+import React, { useMemo, useState } from 'react';
+import { Form } from '@ant-design/compatible';
+import '@ant-design/compatible/assets/index.css';
+
+const layout = {
+  labelCol: {
+    span: 8,
+  },
+  wrapperCol: {
+    span: 16,
+  },
+};
+
+const AuditDetailed = props => {
+  // const [form] = Form.useForm();
+  const { items, form } = props;
+
+  const behavior = useMemo(() => {
+    let data = {};
+    let watchList = {};
+    items.forEach(d => {
+      const item = d.props;
+      if (item.behaviorLinkage) {
+        const key = item.id;
+        item.behaviorLinkage.forEach(b => {
+          const value = b.value;
+          b.targets.forEach(t => {
+            data[t.fieldId] = { key, value };
+          });
+          watchList[key] = true;
+        });
+      }
+    });
+
+    return data;
+  }, [items]);
+
+  const onFinish = values => {
+    console.log(values);
+  };
+
+  const GetComponent = item => {
+    const {
+      id,
+      label,
+      bizAlias,
+      required,
+      placeholder,
+      options,
+      align,
+      statField,
+      hideLabel,
+      objOptions,
+      format,
+      pushToAttendance,
+      labelEditableFreeze,
+      requiredEditableFreeze,
+      unit,
+      extract,
+      link,
+      payEnable,
+      bizType,
+      childFieldVisible,
+      notPrint,
+      verticalPrint,
+      hiddenInApprovalDetail,
+      disabled,
+      notUpper,
+      children, // 子控件
+    } = item.props;
+    // 判断是否属于关联项
+    if (behavior[id]) {
+      const { key, value } = behavior[id];
+      let currentValue = form.getFieldValue(key);
+      // 判断是否需要渲染
+      if (currentValue instanceof Array) {
+        if (currentValue?.indexOf(value) == -1) return null;
+      } else {
+        if (currentValue != value) return null;
+      }
+    }
+
+    const component = DDComponents({ item });
+    if (!component) return null;
+    return (
+      <Form.Item label={bizAlias || label}>
+        {form.getFieldDecorator(id, {
+          rules: [{ required }],
+        })(component)}
+        {notUpper == 1 && <p>大写</p>}
+      </Form.Item>
+    );
+  };
+
+  return (
+    <Form layout="vertical" autoComplete="off">
+      {items.map(item => GetComponent(item))}
+    </Form>
+  );
+};
+
+export default AuditDetailed;

+ 142 - 0
src/pages/PurchaseAdmin/PurchaseList/Detail/AuditFlow.js

@@ -0,0 +1,142 @@
+import React, { useMemo, useEffect, useState, useRef } from 'react';
+import { Steps, Popover } from 'antd';
+import styles from './Index.less';
+import { queryDDProcessesForecast } from '@/services/boom';
+
+const { Step } = Steps;
+
+const ACTOR_TYPE = {
+  approver: '审批人',
+  notifier: '抄送人',
+  audit: '办理人',
+};
+const APPROVAL_TYPE = {
+  MANUAL: '人工审批',
+  AUTO_AGREE: '自动通过',
+  AUTO_REFUSE: '自动拒绝',
+};
+const APPROVAL_METHOD = {
+  ONE_BY_ONE: '依次审批',
+  AND: '会签审批',
+  OR: '或签审批',
+};
+const ACTIVITY_TYPE = {
+  target_select: '自选审批人',
+  target_approval: '指定审批人',
+};
+
+function AuditFlow(props) {
+  const {
+    processCode,
+    deptId = '14169890',
+    userId = '16569001414345099',
+    formComponentValues,
+    activityId,
+    direction,
+    status,
+  } = props;
+  console.log('------------------------------', props);
+  const [flow, setFlow] = useState({ workflowActivityRules: [] });
+  const timerRef = useRef({
+    id: '',
+    status: false,
+  });
+  const current = useMemo(() => {
+    if (!activityId) {
+      return flow.workflowActivityRules.length;
+    } else {
+      return flow.workflowActivityRules.findIndex(item => item.activityId == activityId);
+    }
+  }, [activityId, flow]);
+
+  const renderDesc = item => {
+    return <></>;
+  };
+  const renderAlert = () => {
+    // const audit_comment = history.list[0]?.audit_comment;
+    let item = '';
+    switch (status) {
+      case 0:
+        if (!flow.list || flow.list.FlowNodes?.length == 0) return;
+        item = <Alert message="审批拒绝" type="error" />;
+        break;
+      case 1:
+        item = <Alert message="等待审核中" type="info" />;
+        break;
+      case 2:
+        item = <Alert message={`审批被拒绝`} type="error" />;
+        break;
+      case 3:
+        item = <Alert message="审批通过" type="success" />;
+        break;
+    }
+
+    return <div style={{ marginTop: 20 }}>{item}</div>;
+  };
+  const customDot = (dot, { status, index }) => {
+    let item = flow.workflowActivityRules[index];
+
+    return (
+      <Popover
+        content={
+          <div>
+            节点类型:{ACTIVITY_TYPE[item.activityType]}
+            <br />
+            操作人类型:{ACTOR_TYPE[item.workflowActor?.actorType]}
+            <br />
+            审批类型:{APPROVAL_TYPE[item.workflowActor?.approvalType]}
+            <br />
+            审批方式:{APPROVAL_METHOD[item.workflowActor?.approvalMethod]}
+          </div>
+        }
+      >
+        {dot}
+      </Popover>
+    );
+  };
+
+  const getDetail = async () => {
+    if (!timerRef.current.status) {
+      // 上锁
+      timerRef.current.status = true;
+      try {
+        let flow = await queryDDProcessesForecast({
+          processCode,
+          deptId,
+          userId,
+          formComponentValues,
+        });
+        setFlow(flow);
+      } catch (error) {}
+      setTimeout(() => {
+        // 延时解锁
+        timerRef.current.status = false;
+      }, 2000);
+    } else {
+      clearTimeout(timerRef.current.id);
+      // 延迟调用
+      timerRef.current.id = setTimeout(() => {
+        getDetail();
+      }, 2000);
+    }
+  };
+
+  useEffect(() => {
+    if (!processCode || !formComponentValues) return;
+    getDetail();
+  }, [processCode, formComponentValues]);
+
+  return (
+    <div className={styles.top}>
+      <Steps current={current} progressDot={customDot} direction={direction}>
+        {flow.workflowActivityRules.map(item => (
+          <Step key={item.activityId} title={item?.activityName} />
+        ))}
+        {/* <Step key={item.activityId} title={item?.activityName} description={renderDesc(item)} /> */}
+      </Steps>
+      {status !== undefined && renderAlert()}
+    </div>
+  );
+}
+
+export default AuditFlow;

+ 190 - 1
src/pages/PurchaseAdmin/PurchaseList/Detail/CommitAuditModal.js

@@ -1,13 +1,18 @@
 import React, { useEffect, useState, useRef, useMemo } from 'react';
 import '@ant-design/compatible/assets/index.css';
-import { Modal, Input, Select, message, Cascader, Form } from 'antd';
+import { Modal, Input, Select, message, Cascader, Form, Tabs } from 'antd';
 import { connect } from 'dva';
 import { isArray, result } from 'lodash';
 import { useForm } from 'rc-field-form';
 import { async } from '@antv/x6/lib/registry/marker/async';
+import AuditDetailed from './AuditDetailed';
+import AuditFlow from './AuditFlow';
+import { queryDingSchema } from '@/services/boom';
+import { Form as Form3x } from '@ant-design/compatible';
 
 const { TextArea } = Input;
 const { Option } = Select;
+const { TabPane } = Tabs;
 
 // 提交
 function CommitAuditModal(props) {
@@ -16,18 +21,33 @@ function CommitAuditModal(props) {
   const [data, setData] = useState([]);
   const [length, setLength] = useState(1);
   const [formData, setFromData] = useState({});
+<<<<<<< HEAD
+=======
+  const [auditList, setAuditList] = useState([]); //用于创建Tabs表单
+  const [formComponentValues, setFormComponentValues] = useState({}); //用于创建Tabs表单
+>>>>>>> develop_0715
   const [form] = Form.useForm();
+
   useEffect(() => {
+    if (!visible) return;
     const { edges, nodes } = flowDetail;
     let Id = version.template_node_id;
     const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
     const data = treeData(currentId);
     if (data.length <= 0) setAuditId(currentId);
     setData(data);
+<<<<<<< HEAD
   }, [auditId, version.template_node_id]);
 
   useEffect(() => {
     form.resetFields();
+=======
+  }, [auditId, version.template_node_id, visible]);
+
+  useEffect(() => {
+    form.resetFields();
+    setAuditList([]);
+>>>>>>> develop_0715
   }, [visible]);
 
   const treeData = currentId => {
@@ -40,7 +60,10 @@ function CommitAuditModal(props) {
       });
     };
     fun(list);
+<<<<<<< HEAD
     console.log(list);
+=======
+>>>>>>> develop_0715
     const fun2 = list => {
       const parents = list.filter(item => list.findIndex(node => node.Id == item.parentId) == -1);
       let translator = (parents, children) => {
@@ -87,7 +110,11 @@ function CommitAuditModal(props) {
     let targetIds = edges
       .filter(edge => edge.source.cell == currentId)
       .map(item => item.target.cell);
+<<<<<<< HEAD
     console.log(edges.filter(edge => edge.source.cell == currentId));
+=======
+    edges.filter(edge => edge.source.cell == currentId);
+>>>>>>> develop_0715
     let auditNodes = nodes.filter(node => {
       if (type && node.name != type) {
         return false;
@@ -113,11 +140,113 @@ function CommitAuditModal(props) {
 
   const onChange = value => {
     changeAudit(value[value.length - 1]);
+<<<<<<< HEAD
   };
 
   const onFinish = async () => {
+=======
+    setAuditListFun();
+  };
+  //处理tabs页
+  const setAuditListFun = async () => {
+>>>>>>> develop_0715
     var fieldsValue = await form.validateFields();
+    let addAuditList = [];
+    let result = Object.values(fieldsValue)
+      .map(item => {
+        if (item && Array.isArray(item)) return item;
+      })
+      .filter(item => item)
+      .flat(Infinity);
+    let codeList = [...new Set(result)]
+      .map(Id => {
+        return flowDetail.nodes.find?.(item => item.Id == Id);
+      })
+      .filter(item => item.process_code);
+    for (let i = 0; i < codeList.length; i++) {
+      let res = await queryDingSchema({ process_code: codeList[i].process_code });
+      if (res) {
+        res.data.result.nodeId = codeList[i].Id;
+        addAuditList.push(res.data.result);
+      }
+    }
+    console.log(addAuditList);
+    addAuditList.forEach((item, index) => {
+      let Components = Form3x.create({
+        onValuesChange: (props, changedValues, allValues) => {
+          const { items } = props;
+          console.log(item);
+          formComponentValues[item.nodeId] = items
+            .map(item => {
+              const itemProps = item.props;
+              if (!itemProps.label) return;
+              let val = allValues[itemProps.id];
+              if (val instanceof Object) {
+                return {
+                  name: itemProps.label,
+                  id: itemProps.id,
+                  ...val,
+                };
+              }
+              return {
+                name: itemProps.label,
+                // id: itemProps.id,
+                value: allValues[itemProps.id] || '',
+              };
+            })
+            .filter(item => item);
+          setFormComponentValues({ ...formComponentValues });
+        },
+      })(AuditDetailed);
+      item.FormComponents = <Components items={item.schemaContent.items} />;
+    });
+    setAuditList(addAuditList);
+  };
 
+<<<<<<< HEAD
+=======
+  const getFromData = idList => {
+    const data = formComponentValues;
+    const result = [];
+    //获取流转节点的层级关系
+    let len = 0;
+    let list = [];
+    idList.forEach(item => {
+      if (len < item.length) len = item.length;
+    });
+    for (let i = 0; i < len; i++) {
+      idList.forEach(item => {
+        if (item && item[i]) list.push(item[i]);
+      });
+    }
+    let firstList = [...new Set(list)];
+    // let firstList = idList[0];
+    // for (let i = 1; i < idList.length; i++) {
+    //   let item = idList[i];
+    //   item.forEach(itemId => {
+    //     let idx = firstList.findIndex(id => id == itemId);
+    //     if (idx > 0 && !firstList.find(cur => cur == item[idx - 1])) {
+    //       firstList.splice(idx, 0, item[i - 1]);
+    //     }
+    //   });
+    // }
+    firstList.forEach(id => {
+      let approvalNode = flowDetail.nodes.find?.(item => item.Id == id);
+      const formItem = {
+        processCode: approvalNode.process_code,
+        originatorUserId: '16569001414345099',
+        deptId: '14169890',
+        formComponentValues: data[approvalNode.Id],
+      };
+      result.push(JSON.stringify(formItem));
+    });
+    return result;
+  };
+  const onFinish = async () => {
+    var fieldsValue = await form.validateFields();
+    console.log(formComponentValues);
+    let hasFlowId = true; //是否都绑定审批节点
+>>>>>>> develop_0715
     const getFlowPath = node => {
       //[134, 135]
       let itemData = {};
@@ -130,6 +259,11 @@ function CommitAuditModal(props) {
         data.node_level_id = approvalNode?.flow_id ? 1 : 0;
         data.template_node_id = approvalNode?.Id;
         index++;
+        if (approvalNode?.Id) {
+          if (!approvalNode?.flow_id) {
+            hasFlowId = false;
+          }
+        }
         const res = Function(node[index], index);
         if (res) {
           data.flow_path = [res];
@@ -145,6 +279,16 @@ function CommitAuditModal(props) {
       })
       .filter(item => item);
     let serviceNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.next_template_node_id);
+<<<<<<< HEAD
+=======
+    if (!serviceNode) {
+      message.error('请选择需要流转的业务节点。');
+      return;
+    }
+
+    const flowPath = result.map(item => getFlowPath(item));
+    const formList = getFromData(result);
+>>>>>>> develop_0715
     let params = {
       desc: fieldsValue.desc,
       // 审核流程id
@@ -170,6 +314,7 @@ function CommitAuditModal(props) {
       params.flow_id = approvalNode?.flow_id || 0;
       params.node_level_id = approvalNode?.flow_id ? 1 : 0;
       params.template_node_id = result[0][0]; // 将要流转的节点审批节点
+<<<<<<< HEAD
     } else {
       //多节点审批
       params.template_node_id = result[0][0]; // 将要流转的节点审批节点
@@ -186,6 +331,33 @@ function CommitAuditModal(props) {
     // setAuditId();
     onOk(params);
   };
+=======
+      params.form_list = formList; //创建钉钉表单所需数据
+      if (approvalNode?.Id) {
+        if (!approvalNode?.flow_id) {
+          hasFlowId = false;
+        }
+      }
+    } else {
+      //多节点审批
+      params.template_node_id = result[0][0]; // 将要流转的节点审批节点
+      params.flow_path = flowPath;
+      params.form_list = formList; //创建钉钉表单所需数据
+    }
+    if (!hasFlowId) {
+      message.error('当前存在审批节点未绑定审批流程!请联系管理员。');
+      return;
+    }
+
+    console.log(JSON.stringify(params));
+    console.log(params);
+    onOk(params);
+  };
+
+  const onTabChange = key => {
+    console.log('=====================', key);
+  };
+>>>>>>> develop_0715
 
   const CascaderNode = index => {
     return (
@@ -231,6 +403,23 @@ function CommitAuditModal(props) {
           <Input.TextArea />
         </Form.Item>
       </Form>
+<<<<<<< HEAD
+=======
+      <Tabs defaultActiveKey="1" onChange={onTabChange}>
+        {auditList.map((item, idx) => (
+          // <TabPane tab={item.label} key={`${item.Id}_${item.label}`}>
+          //   <AuditDetailed />
+          // </TabPane>
+          <TabPane tab={item.name} key={`${idx}_${item.title}`}>
+            {item.FormComponents}
+            <AuditFlow
+              processCode={item.formCode}
+              formComponentValues={formComponentValues[item.nodeId]}
+            />
+          </TabPane>
+        ))}
+      </Tabs>
+>>>>>>> develop_0715
     </Modal>
   );
 }

+ 0 - 143
src/pages/PurchaseAdmin/PurchaseList/Detail/CommitAuditModalNew.js

@@ -1,143 +0,0 @@
-import React, { useEffect, useState, useRef, useMemo } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Modal, Input, Select, message } from 'antd';
-import { connect } from 'dva';
-
-const { TextArea } = Input;
-const { Option } = Select;
-
-// 提交
-function CommitAuditModal(props) {
-  const { visible, onClose, onOk, form, loading, version, versionList, flowDetail } = props;
-  const [auditId, setAuditId] = useState();
-  const handleOk = () => {
-    form.validateFields((err, fieldsValue) => {
-      console.log("-------",fieldsValue )
-      if (err) return;
-      let approvalNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.node_id);
-      let serviceNode = flowDetail.nodes.find?.(
-        item => item.Id == fieldsValue.next_template_node_id
-      );
-      let params = {
-        desc: fieldsValue.desc,
-        // 审核流程id
-        flow_id: approvalNode?.flow_id || 0,
-        node_level_id: approvalNode?.flow_id ? 1 : 0,
-
-        id: version.id,
-        project_id: version.project_id,
-        cur_template_node_id: version.template_node_id * 1, // 当前节点
-        template_node_id: approvalNode?.Id, // 将要流转的节点审批节点
-        next_template_node_id: serviceNode.Id * 1, // 审核完成后的业务节点
-
-        // 模板id.一致就行
-        template_id: version.template_id,
-        cur_template_id: version.template_id,
-        next_template_id: version.template_id,
-      };
-      if (approvalNode?.Id) {
-        if (!approvalNode?.flow_id) {
-          message.error('审批节点未绑定审批流程!请联系管理员。');
-          return;
-        }
-      }
-      // // 判断业务节点是否允许多清单
-      // if (!serviceNode.muti_version) {
-      //   //audit_status=4 表示为清单推进后留存的副本.不计入多清单计算
-      //   let serviceVersion = versionList.find(
-      //     item => item.audit_status != 4 && item.template_node_id == serviceNode.Id
-      //   );
-      //   if (serviceVersion) {
-      //     message.error(
-      //       `流转失败!业务节点【${serviceNode.label}】为单清单节点。已存在清单【${serviceVersion.version_name}】。`
-      //     );
-      //     return;
-      //   }
-      // }
-
-
-      setAuditId();
-      // onOk(params);
-    });
-  };
-  const currentNodeId = useMemo(() => {
-    let Id = version.template_node_id;
-    return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
-  }, [flowDetail, version]);
-  /**
-   *
-   * @param {*} currentId 当前节点
-   * @param {*} type 下一个节点的类型  custom-circle: 审批节点   custom-rect: 业务节点
-   * @returns
-   */
-  const getNextNodes = (currentId, type) => {
-    const { edges, nodes } = flowDetail;
-    if (!currentId) return [];
-    let targetIds = edges
-      .filter(edge => edge.source.cell == currentId)
-      .map(item => item.target.cell);
-    let auditNodes = nodes.filter(node => {
-      if (type && node.name != type) {
-        return false;
-      }
-      return targetIds.indexOf(node.id) != -1;
-    });
-    return auditNodes || [];
-  };
-
-  const changeAudit = id => {
-    let node = flowDetail.nodes.find?.(item => item.Id == id);
-    setAuditId(node.node_id);
-  };
-
-  return (
-    <Modal
-      confirmLoading={loading}
-      destroyOnClose
-      title="提交流转目标"
-      visible={visible}
-      onCancel={() => {
-        setAuditId();
-        onClose();
-      }}
-      onOk={handleOk}
-    >
-      <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="审批节点">
-        {form.getFieldDecorator('node_id')(
-          <Select style={{ width: '100%' }} onChange={changeAudit}>
-            {getNextNodes(currentNodeId, 'custom-circle').map(item => (
-              <Option key={item.Id}>{item.label}</Option>
-            ))}
-          </Select>
-        )}
-      </Form.Item>
-      {/* <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="审批节点2">
-        {form.getFieldDecorator('nod_id')(
-          <Select style={{ width: '100%' }} onChange={changeAudit}>
-            {getNextNodes(auditId || currentNodeId, 'custom-circle').map(item => (
-              <Option key={item.Id}>{item.label}</Option>
-            ))}
-          </Select>
-        )}
-      </Form.Item> */}
-      <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="业务节点">
-        {form.getFieldDecorator('next_template_node_id')(
-          <Select style={{ width: '100%' }}>
-            {getNextNodes(auditId || currentNodeId, auditId ? 'custom-rect' : '').map(item => (
-              <Option key={item.Id}>{item.label}</Option>
-            ))}
-          </Select>
-        )}
-      </Form.Item>
-      <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="备注信息">
-        {form.getFieldDecorator('desc')(<Input.TextArea />)}
-      </Form.Item>
-    </Modal>
-  );
-}
-
-export default connect(({ xflow, detail }) => ({
-  flowDetail: xflow.flowDetail,
-  versionList: detail.versionList,
-}))(Form.create()(CommitAuditModal));

+ 4 - 0
src/pages/PurchaseAdmin/PurchaseList/Detail/FlowModal.js

@@ -128,6 +128,10 @@ function FlowModal(props) {
   const handleChangeClick = item => {
     let file = isOut ? 'newList' : 'detail';
     let type = item.flow_id ? '/queryAuditRecord' : '/queryAuditExcel';
+<<<<<<< HEAD
+=======
+    console.log(`${file}${type}`, item);
+>>>>>>> develop_0715
     dispatch({
       type: `${file}${type}`,
       payload: {

+ 48 - 7
src/pages/PurchaseAdmin/PurchaseList/Detail/Index.js

@@ -22,6 +22,7 @@ import MergeModal from './MergeModal';
 import { GetTokenFromUrl, getToken } from '@/utils/utils';
 import { queryDetail } from '@/services/boom';
 import HistoryDrawer from './HistoryDrawer';
+import AuditFlow from './AuditFlow';
 const LocalData = localStorage.luckysheet;
 
 const { Option } = Select;
@@ -41,6 +42,7 @@ function Detail(props) {
     flowDetail,
     versionTree,
     match: { params },
+    instanceDetail,
   } = props;
   const [versionTreeVisible, setVersionTreeVisible] = useState(false);
   const [commentVisible, setCommentVisible] = useState(false);
@@ -68,6 +70,7 @@ function Detail(props) {
   const sheetRef2 = useRef();
   const sheetRef3 = useRef();
   const fileRef = useRef();
+  const userRef = useRef();
   const statusRef = useRef({
     edit: false,
     compare: false,
@@ -77,6 +80,26 @@ function Detail(props) {
   const projectId = parseInt(params.projectId);
   const templateId = parseInt(params.templateId);
 
+  const auditDetail = useMemo(() => {
+    const { tasks, form_component_values } = instanceDetail;
+    let data = {
+      processCode: '',
+      deptId: '14169890',
+      userId: '16569001414345099',
+      formComponentValues: form_component_values?.filter(item => item.name),
+      activityId: '',
+      status: version.active_audit,
+    };
+    if (version?.flow_id && tasks?.length > 0) {
+      let item = flowDetail.nodes.find(item => item.Id == version.template_node_id);
+      if (!item) return data;
+      data.processCode = item.process_code;
+      data.activityId = tasks[tasks.length - 1]?.activity_id;
+    }
+    console.log('====================auditDetail ', data);
+    return data;
+  }, [instanceDetail, version]);
+
   const flow = useMemo(() => {
     let data = {
       active: 0,
@@ -97,7 +120,6 @@ function Detail(props) {
       item.currentNode = item.list.FlowNodes[item.current];
       data = item;
     }
-
     return data;
   }, [auditList, version]);
   const active_audit = flow.active_audit;
@@ -569,7 +591,7 @@ function Detail(props) {
         }
         return true;
       };
-      console.log('是否有权限提交流转   ', getIsSubmit());
+      // console.log('是否有权限提交流转   ', getIsSubmit());
       if (getIsSubmit() && version.audit_status != 3)
         menuList.push(<Menu.Item key="commitAudit">提交流转</Menu.Item>);
 
@@ -769,6 +791,12 @@ function Detail(props) {
           version_id: version.version_id,
         },
       });
+      dispatch({
+        type: 'detail/queryDingInstanceDetail',
+        payload: {
+          process_instance_id: version.ding_instance_id, //创建表单成功返回的id
+        },
+      });
     }
   };
 
@@ -796,8 +824,13 @@ function Detail(props) {
     });
   };
 
-  const getUser = user => {
-    setUser(user);
+  const getUser = newUser => {
+    try {
+      if (JSON.stringify(newUser) != JSON.stringify(userRef.current)) {
+        userRef.current = newUser;
+        setUser(newUser);
+      }
+    } catch (error) {}
   };
 
   const renderNode = () => {
@@ -914,9 +947,16 @@ function Detail(props) {
           onChange={e => exportExcl(e.target.files)}
         />
       </div>
-      <TimeNode flow={flow} isAuditor={isAuditor} onApprove={onApprove}></TimeNode>
-
-      {renderAlert()}
+      {/* <TimeNode flow={flow} isAuditor={isAuditor} onApprove={onApprove}></TimeNode> */}
+      <AuditFlow
+        status={auditDetail.status}
+        processCode={auditDetail.processCode}
+        deptId="14169890"
+        userId="16569001414345099"
+        activityId={auditDetail.activityId}
+        formComponentValues={auditDetail.formComponentValues}
+      />
+      {/* {renderAlert()} */}
       {/* 判断是否为比对模式 */}
       {compareList.length == 2 ? (
         <>
@@ -1025,6 +1065,7 @@ export default connect(({ detail, user, xflow, loading }) => ({
   fileList: detail.fileList,
   history: detail.history,
   comment: detail.comment,
+  instanceDetail: detail.dingInstanceDetail,
   currentUser: user.currentUser,
   roleList: detail.roleList,
   versionList: detail.versionList,

+ 18 - 0
src/pages/PurchaseAdmin/PurchaseList/Detail/models/detail.js

@@ -31,6 +31,8 @@ import {
   queryVersionsTree,
   queryAuditExcel,
   queryAuditRecord,
+  queryDingSchema,
+  queryDingInstanceDetail,
 } from '@/services/boom';
 import { queryRole } from '@/services/SysAdmin';
 import { setCurrentUser } from '@/utils/authority';
@@ -73,6 +75,7 @@ export default {
     authority: [],
     versionTree: [],
     auditExcel: [],
+    dingInstanceDetail: [],
   },
 
   effects: {
@@ -513,6 +516,21 @@ export default {
         callback && callback(response.data?.all);
       }
     },
+    *queryDingSchema({ payload, callback }, { call, put }) {
+      const response = yield call(queryDingSchema, payload);
+      if (response) {
+        callback && callback(response.data?.all);
+      }
+    },
+    *queryDingInstanceDetail({ payload, callback }, { call, put }) {
+      const response = yield call(queryDingInstanceDetail, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { dingInstanceDetail: response.data?.process_instance },
+        });
+      }
+    },
   },
 
   reducers: {

+ 3 - 0
src/pages/PurchaseAdmin/PurchaseList/Flow/List.js

@@ -50,6 +50,9 @@ function List(props) {
     dispatch({
       type: 'flow/getRoleList',
     });
+    // dispatch({
+    //   type: 'flow/queryDingTemplateList',
+    // });
   }, []);
 
   return (

+ 12 - 0
src/pages/PurchaseAdmin/PurchaseList/Flow/models/flow.js

@@ -6,6 +6,7 @@ import {
   queryBoomFlowDetail,
   updateNode,
   queryFlowList,
+  queryDingTemplateList,
 } from '@/services/boom';
 import { queryRole } from '@/services/SysAdmin';
 import { queryProject } from '@/services/PurchaseList';
@@ -20,6 +21,7 @@ export default {
     projectList: [],
     current: {},
     roleList: [],
+    templateList: [],
   },
 
   effects: {
@@ -100,6 +102,16 @@ export default {
         callback && callback();
       }
     },
+    *queryDingTemplateList({ payload }, { call, put }) {
+      const response = yield call(queryDingTemplateList, payload);
+      if (response) {
+        console.log('-[-----------------------------------', response.data.result);
+        yield put({
+          type: 'save',
+          payload: { templateList: response.data.result },
+        });
+      }
+    },
   },
 
   reducers: {

+ 34 - 0
src/services/boom.js

@@ -1,3 +1,4 @@
+import { message } from 'antd';
 import request from '@/utils/request';
 import { async } from '@antv/x6/lib/registry/marker/async';
 import { stringify } from 'qs';
@@ -103,6 +104,16 @@ export async function queryAuditExcel(params) {
 export async function queryAuditRecord(params) {
   return request(`/api/v1/purchase/audit/record?${stringify(params)}`);
 }
+//查询表单数据接口
+export async function queryDingSchema(params) {
+  return request(`/api/v1/purchase/bom/ding/schema?${stringify(params)}`);
+}
+export async function queryDingInstanceDetail(params) {
+  return request(`/api/v1/purchase/bom/ding/instance-detail`, {
+    method: 'POST',
+    body: params,
+  });
+}
 /**
  * 查看项目流程列表
  * project_id
@@ -284,3 +295,26 @@ export async function queryRecordSheet(data) {
     body: data,
   });
 }
+export async function queryDingTemplateList() {
+  return request(`/purchase/bom/ding/template/list`);
+}
+
+export async function queryDDdepList(data) {
+  let res = await request(`/api/v1/purchase/bom/ding/department-list`, {
+    method: 'POST',
+    body: data,
+  });
+  return res.data.result;
+}
+
+export async function queryDDProcessesForecast(data) {
+  let res = await request(`/api/v1/purchase/bom/ding/processes-forecast`, {
+    method: 'POST',
+    body: data,
+  });
+  if (res.data.message) {
+    // message.error(res.data.message);
+    throw new Error(res.data.message);
+  }
+  return res.data.result;
+}