浏览代码

迁移bom采购清单页面/修改OAmodel的nameSpace名称

Renxy 2 年之前
父节点
当前提交
835305c2a0

+ 31 - 0
.umirc.ts

@@ -262,6 +262,37 @@ export default defineConfig({
         },
       ],
     },
+    {
+      name: 'BOM清单',
+      path: '/bom',
+      hideChildrenInMenu: true,
+      icon: 'https://gt-digitization.oss-cn-hangzhou.aliyuncs.com/doc/department/2023-04/flowIcon.png',
+      routes: [
+        {
+          name: '采购清单',
+          path: '/bom/home',
+          component: './Flow/index',
+        },
+        {
+          name: '流程管理',
+          path: '/bom/flow-list',
+          component: './Flow/Audit',
+          hideInMenu: true,
+        },
+        {
+          name: '审核列表',
+          path: '/bom/auth',
+          component: './Flow/Audit',
+          hideInMenu: true,
+        },
+        {
+          name: '已提交审批',
+          path: '/bom/submit',
+          component: './Flow/Audit',
+          hideInMenu: true,
+        },
+      ],
+    },
 
     // {checkReport(3) && (
     //   // <Menu.Item key="/home/report/finance">

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

@@ -45,7 +45,7 @@ function Audit(props) {
 
   useEffect(() => {
     dispatch({
-      type: 'flow/queryProcessFlows',
+      type: 'flowOa/queryProcessFlows',
       payload: { ids: Number(curItem.id) },
     });
     dispatch({
@@ -78,7 +78,7 @@ function Audit(props) {
         process_json: JSON.stringify(flowDetail),
         process_simple_json: simpleFlowDteail,
       };
-      dispatch({ type: 'flow/saveAuditFlowInfo', payload: param });
+      dispatch({ type: 'flowOa/saveAuditFlowInfo', payload: param });
       return;
     }
     await ref.current?.getGraphData?.((data, simpleNodes) => {
@@ -89,7 +89,7 @@ function Audit(props) {
         process_json: data,
         process_simple_json: simpleNodes,
       };
-      dispatch({ type: 'flow/saveAuditFlowInfo', payload: param });
+      dispatch({ type: 'flowOa/saveAuditFlowInfo', payload: param });
     });
   };
   return (
@@ -97,7 +97,7 @@ function Audit(props) {
       extra={[
         <Button
           key={1}
-          loading={loading['flow/saveAuditFlowInfo']}
+          loading={loading['flowOa/saveAuditFlowInfo']}
           type="primary"
           onClick={handleSaveClick}
         >
@@ -133,12 +133,12 @@ function Audit(props) {
     </PageContent>
   );
 }
-export default connect(({ flow, loading, user, xflow }) => ({
-  roleList: flow.roleList,
+export default connect(({ flowOa, loading, user, xflow }) => ({
+  roleList: flowOa.roleList,
   loading: loading.effects,
   formItems: xflow.formData,
-  flowDetail: flow.flowDetail,
-  formData: flow.formData,
-  simpleFlowDteail: flow.simpleFlowDteail,
+  flowDetail: flowOa.flowDetail,
+  formData: flowOa.formData,
+  simpleFlowDteail: flowOa.simpleFlowDteail,
   userList: user.list,
 }))(Audit);

+ 0 - 1
src/pages/Flow/AuditModal.js

@@ -19,7 +19,6 @@ function AuditModal(props) {
   };
 
   useEffect(() => {
-    console.log('===============', data);
     if (visible) form.resetFields();
   }, [visible]);
   return (

+ 2 - 2
src/pages/Flow/components/AuditDetailed.js

@@ -7,7 +7,7 @@ const AuditDetailed = (props) => {
   const { items, form, onValuesChange } = props;
   const data = useMemo(() => {
     let linkedData = {};
-    items.forEach((d) => {
+    items?.forEach((d) => {
       const item = d.props;
       if (item.linked) {
         linkedData = { ...linkedData, [item.id]: item.linked };
@@ -81,7 +81,7 @@ const AuditDetailed = (props) => {
       onValuesChange={onValuesChange}
       onFinish={onFinish}
     >
-      {items.map((item) => GetComponent(item))}
+      {items?.map((item) => GetComponent(item))}
     </Form>
   );
 };

+ 12 - 12
src/pages/Flow/index.js

@@ -73,7 +73,7 @@ function Audit(props) {
             if (data?.code == 200) {
               message.success('删除成功');
               dispatch({
-                type: 'flow/queryAuditList',
+                type: 'flowOa/queryAuditList',
                 payload: {
                   flow_type: 1,
                 },
@@ -87,7 +87,7 @@ function Audit(props) {
 
   const handleCopy = async (values) => {
     dispatch({
-      type: 'flow/addAudit',
+      type: 'flowOa/addAudit',
       payload: {
         ...values,
         // flow_type: 1,
@@ -108,7 +108,7 @@ function Audit(props) {
   };
   const handleAuditOk = (values) => {
     dispatch({
-      type: 'flow/addAudit',
+      type: 'flowOa/addAudit',
       payload: {
         ...values,
         // flow_type: 1,
@@ -128,23 +128,23 @@ function Audit(props) {
   const setCurrentNode = (item) => {
     localStorage.setItem('currentAudit', JSON.stringify(item));
     dispatch({
-      type: 'flow/save',
+      type: 'flowOa/save',
       payload: {
         current: item.list,
       },
     });
-    navigate('/flow/audit');
+    navigate('/flowOa/audit');
   };
 
   useEffect(() => {
     dispatch({
-      type: 'flow/queryAuditList',
+      type: 'flowOa/queryAuditList',
       payload: {
         flow_type: 1,
       },
     });
     dispatch({
-      type: 'flow/queryClassify',
+      type: 'flowOa/queryClassify',
       payload: {
         c_type: 1,
       },
@@ -165,7 +165,7 @@ function Audit(props) {
       </Button>
       <Table
         style={{ marginTop: 20 }}
-        loading={loading['flow/queryAuditList']}
+        loading={loading['flowOa/queryAuditList']}
         rowKey="id"
         dataSource={list}
         columns={columns}
@@ -173,7 +173,7 @@ function Audit(props) {
 
       <AuditModal
         data={data}
-        loading={loading['flow/addAudit']}
+        loading={loading['flowOa/addAudit']}
         visible={visible.audit}
         onOk={data ? handleCopy : handleAuditOk}
         onCancel={() => changeVisible('audit', false)}
@@ -183,8 +183,8 @@ function Audit(props) {
     </PageContent>
   );
 }
-export default connect(({ flow, loading }) => ({
-  list: flow.auditList,
-  classify: flow.classify,
+export default connect(({ flowOa, loading }) => ({
+  list: flowOa.auditList,
+  classify: flowOa.classify,
   loading: loading.effects,
 }))(Audit);

+ 2 - 2
src/pages/Flow/models/flow.js

@@ -44,7 +44,7 @@ import { message } from 'antd';
 // }
 
 export default {
-  namespace: 'flow',
+  namespace: 'flowOa',
   state: {
     flowDetail: { nodes: [], edges: [] },
     formData: {},
@@ -114,7 +114,7 @@ export default {
         message.success('保存成功');
         callback && callback();
         yield put({
-          type: 'flow/queryProcessFlows',
+          type: 'flowOa/queryProcessFlows',
           payload: { ids: Number(payload.id) },
         });
       } catch (error) {}

+ 135 - 0
src/pages/bom/Flow/Audit.js

@@ -0,0 +1,135 @@
+import React, { useState, useEffect, useRef, useMemo } from 'react';
+import { Form, Select, Button, Table, Input, Checkbox, Divider, Tabs } from 'antd';
+import { connect } from 'dva';
+import AuditNodeModal from './AuditNodeModal';
+import AuditModal from './AuditModal';
+import styles from './Audit.less';
+import router from 'umi/router';
+import Flow, { FLOW_TYPE } from '@/components/Flow';
+import AuditForm from '@/components/AuditForm';
+import { async } from '@antv/x6/lib/registry/marker/async';
+const { Option } = Select;
+const { TabPane } = Tabs;
+
+const FLOWID = 2;
+
+function Audit(props) {
+  const {
+    roleList,
+    currentItem,
+    dispatch,
+    formItems,
+    formData,
+    flowDetail,
+    simpleFlowDteail,
+    currentUser,
+    loading,
+  } = props;
+  const ref = useRef();
+  const permission = currentUser.Permission;
+
+  const curItem = useMemo(() => {
+    let item = localStorage.getItem('currentAudit');
+    return JSON.stringify(currentItem) == '{}' ? JSON.parse(item) : currentItem;
+  }, [currentItem, localStorage.getItem('currentAudit')]);
+
+  const editMode = useMemo(() => {
+    // 判断是否有权限
+    if (permission['func-01-point-bom-flow']) {
+      return 1;
+    }
+    // 判断是否为创建者
+    if (currentUser.IsSuper) {
+      return 1;
+    }
+
+    return 2;
+  }, [permission, flowDetail]);
+
+  useEffect(() => {
+    dispatch({
+      type: 'flow/queryProcessFlows',
+      payload: { ids: Number(curItem.id) },
+    });
+    dispatch({
+      type: 'user/getRoleList',
+    });
+    dispatch({
+      type: 'user/fetch',
+    });
+
+    dispatch({
+      type: 'user/fetchDepV2',
+    });
+  }, []);
+
+  const onChange = values => {
+    dispatch({
+      type: 'xflow/save',
+      payload: {
+        formData: values,
+      },
+    });
+  };
+
+  const handleSaveClick = async () => {
+    //只修改表单不渲染xflow getGraphData方法找不到,保存接口返回的flowDetail数据
+    if (!ref.current?.getGraphData) {
+      let param = {
+        // name: curItem.name,
+        id: Number(curItem.id),
+        form_json: JSON.stringify(formItems),
+        process_json: JSON.stringify(flowDetail),
+        process_simple_json: simpleFlowDteail,
+      };
+      dispatch({ type: 'flow/saveAuditFlowInfo', payload: param });
+      return;
+    }
+    await ref.current?.getGraphData?.((data, simpleNodes) => {
+      let param = {
+        // name: curItem.name,
+        id: Number(curItem.id),
+        form_json: JSON.stringify(formItems),
+        process_json: data,
+        process_simple_json: simpleNodes,
+      };
+      localStorage.saveAuditFlowInfo = JSON.stringify(param)
+      dispatch({ type: 'flow/saveAuditFlowInfo', payload: param });
+    });
+  };
+  return (
+    <div style={{ position: 'relative' }}>
+      <p>{curItem.name}</p>
+      <Tabs defaultActiveKey="1">
+        <TabPane tab="表单设计" key="1">
+          <AuditForm value={formData} onChange={values => onChange(values)} />
+        </TabPane>
+        <TabPane tab="流程控制" key="2">
+          <Flow
+            meta={{ type: 'edit', editMode, flowId: curItem.id }}
+            flowDetail={flowDetail}
+            ref={ref}
+          />
+        </TabPane>
+      </Tabs>
+      <Button
+        loading={loading['flow/saveAuditFlowInfo']}
+        type="primary"
+        onClick={handleSaveClick}
+        style={{ position: 'absolute', right: 0, top: 0 }}
+      >
+        保存
+      </Button>
+    </div>
+  );
+}
+export default connect(({ flow, loading, user, xflow }) => ({
+  roleList: flow.roleList,
+  currentItem: flow.current,
+  loading: loading.effects,
+  formItems: xflow.formData,
+  flowDetail: flow.flowDetail,
+  formData: flow.formData,
+  currentUser: user.currentUser,
+  simpleFlowDteail: flow.simpleFlowDteail,
+}))(Audit);

+ 16 - 0
src/pages/bom/Flow/Audit.less

@@ -0,0 +1,16 @@
+.box {
+  margin-bottom: 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.btns {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+  :global {
+    .ant-btn {
+      margin-right: 20px;
+    }
+  }
+}

+ 103 - 0
src/pages/bom/Flow/AuditList.js

@@ -0,0 +1,103 @@
+import React, { useState, useEffect } from 'react';
+import { Form, Select, Button, Table, Input, Checkbox, Divider } from 'antd';
+import { connect } from 'dva';
+import AuditNodeModal from './AuditNodeModal';
+import AuditModal from './AuditModal';
+import styles from './Audit.less';
+import router from 'umi/router';
+
+const { Option } = Select;
+
+function Audit(props) {
+  const { userList, list = [], dispatch, loading } = props;
+  const [form] = Form.useForm();
+  const [visible, setVisible] = useState({
+    audit: false,
+    auditNode: false,
+  });
+  const columns = [
+    {
+      title: '审批流名称',
+      dataIndex: ['list', 'name'],
+    },
+    {
+      title: '操作',
+      render: (item, index) => (
+        <>
+          <a
+            onClick={() => {
+              setCurrentNode(item);
+            }}
+          >
+            编辑
+          </a>
+        </>
+      ),
+    },
+  ];
+  const handleAuditOk = values => {
+    console.log(values);
+    dispatch({
+      type: 'flow/addAudit',
+      payload: values,
+      callback: () => {
+        changeVisible('audit', false);
+      },
+    });
+  };
+  const changeVisible = (type, visible) => {
+    setVisible({
+      ...visible,
+      [type]: visible,
+    });
+  };
+  const setCurrentNode = item => {
+    if (item?.list) localStorage.setItem('currentAudit', JSON.stringify(item.list));
+    dispatch({
+      type: 'flow/save',
+      payload: {
+        current: item.list,
+      },
+    });
+    router.push('/home/audit');
+  };
+
+  useEffect(() => {
+    dispatch({
+      type: 'flow/queryAuditList',
+    });
+  }, []);
+
+  return (
+    <div>
+      <div className={styles.box}>
+        <Button onClick={() => router.go(-1)}>返回</Button>
+        <Form layout="inline" name="basic" autoComplete="off" form={form}>
+          <Form.Item>
+            <Button onClick={() => changeVisible('audit', true)} type="primary">
+              新建流程
+            </Button>
+          </Form.Item>
+        </Form>
+      </div>
+
+      <Table
+        loading={loading['flow/queryAuditList']}
+        rowKey="id"
+        dataSource={list}
+        columns={columns}
+      />
+      <AuditModal
+        loading={loading['flow/addAudit']}
+        visible={visible.audit}
+        onOk={handleAuditOk}
+        onCancel={() => changeVisible('audit', false)}
+      />
+    </div>
+  );
+}
+export default connect(({ user, flow, loading }) => ({
+  userList: user.list,
+  list: flow.auditList,
+  loading: loading.effects,
+}))(Audit);

+ 40 - 0
src/pages/bom/Flow/AuditModal.js

@@ -0,0 +1,40 @@
+import React, { useEffect } from 'react';
+import { Modal, Input, Table, Select, Form, Radio } from 'antd';
+const { Option } = Select;
+
+// 审批意见
+function AuditModal(props) {
+  const { visible, onCancel, onOk, userList = [], data = {}, loading } = props;
+  const [form] = Form.useForm();
+  const formLayout = { labelCol: { span: 4 }, wrapperCol: { span: 14 } };
+
+  const handleOk = async () => {
+    let fieldsValue = await form.validateFields();
+    onOk(fieldsValue);
+  };
+
+  useEffect(() => {
+    if (visible) form.resetFields();
+  }, [visible]);
+  return (
+    <Modal
+      confirmLoading={loading}
+      destroyOnClose
+      title="流程"
+      visible={visible}
+      onCancel={onCancel}
+      onOk={handleOk}
+    >
+      <Form {...formLayout} form={form}>
+        <Form.Item label="流程名称" name="name">
+          <Input />
+        </Form.Item>
+        <Form.Item label="详情" name="desc">
+          <Input.TextArea />
+        </Form.Item>
+      </Form>
+    </Modal>
+  );
+}
+
+export default AuditModal;

+ 62 - 0
src/pages/bom/Flow/AuditNodeModal.js

@@ -0,0 +1,62 @@
+import React, { useEffect } from 'react';
+import { InputNumber, Modal, Input, Table, Select, Form, Radio } from 'antd';
+const { Option } = Select;
+
+// 审批意见
+function AuditModal(props) {
+  const { visible, onCancel, onOk, roleList = [], data = {}, loading } = props;
+  const [form] = Form.useForm();
+  const formLayout = { labelCol: { span: 4 }, wrapperCol: { span: 14 } };
+
+  const handleOk = async () => {
+    let fieldsValue = await form.validateFields();
+    // 如果id不存在则使用时间戳作为id
+    fieldsValue.id = data?.id || new Date() * 1;
+    onOk(fieldsValue);
+  };
+
+  useEffect(() => {
+    if (visible) form.resetFields();
+  }, [visible]);
+
+  return (
+    <Modal
+      confirmLoading={loading}
+      title="审批节点"
+      visible={visible}
+      onCancel={onCancel}
+      onOk={handleOk}
+    >
+      <Form {...formLayout} form={form} initialValues={data}>
+        <Form.Item label="节点名" name="node">
+          <Input />
+        </Form.Item>
+        {/* <Form.Item label="审批级别" name="seq">
+          <InputNumber style={{ width: '100%' }} step={1} min={1} />
+        </Form.Item> */}
+        <Form.Item label="审批角色" name="audit_role">
+          <Select
+            showSearch
+            style={{ width: '100%' }}
+            filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
+          >
+            {roleList &&
+              roleList.filter(item => item.RoleType == 4).map(item => (
+                <Option key={item.ID} value={item.ID + ''}>
+                  {item.Name}
+                </Option>
+              ))}
+          </Select>
+        </Form.Item>
+        {/* <Form.Item initialValue={data?.seq_relate || 1} label="审批关系" name="seq_relate">
+          <Radio.Group>
+            <Radio value={1}>或</Radio>
+            <Radio value={2}>并</Radio>
+          </Radio.Group>
+        </Form.Item> */}
+      </Form>
+    </Modal>
+  );
+}
+
+export default AuditModal;

+ 112 - 0
src/pages/bom/Flow/Flow.js

@@ -0,0 +1,112 @@
+import Flow, { FLOW_TYPE } from '@/components/Flow';
+import { connect } from 'dva';
+import React, { useEffect } from 'react';
+import { UnityAction } from '@/utils/utils';
+import { Button, Spin } from 'antd';
+import router from 'umi/router';
+
+@connect(({ xflow, user }) => ({
+  flowDetail: xflow.flowDetail,
+  currentUser: user.currentUser,
+  permission: user.currentUser.Permission,
+}))
+class FlowPage extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = { spinning: false };
+  }
+
+  onUpdate(node) {
+    const { dispatch, flowDetail } = this.props;
+    let params = {
+      ...node,
+      id: node.Id,
+      node_type: node.name == 'custom-circle' ? 1 : 0,
+
+      data: JSON.stringify(node.data),
+      project_id: flowDetail.ProjectId,
+      template_id: flowDetail.Id,
+      template_name: flowDetail.Name,
+    };
+    delete params.node_id;
+    dispatch({
+      type: 'flow/updateNode',
+      payload: {
+        templateId: flowDetail.Id,
+        nodeId: node.Id,
+        body: params,
+      },
+      callback: () => {
+        // this.setState({ spinning: false });
+      },
+    });
+  }
+
+  componentDidMount() {
+    const {
+      dispatch,
+      match: {
+        params: { flowId },
+      },
+    } = this.props;
+    dispatch({
+      type: 'xflow/queryOSSData',
+    });
+    dispatch({
+      type: 'xflow/queryBoomFlowDetail',
+      payload: {
+        id: flowId,
+      },
+    });
+    dispatch({
+      type: 'xflow/queryAuditList',
+    });
+    dispatch({
+      type: 'xflow/fetchDepV2',
+    });
+
+    UnityAction.on('NODE_SAVE', nodeConfig => {
+      this.onUpdate(nodeConfig);
+      // this.setState({ spinning: true });
+    });
+  }
+  componentWillUnmount() {
+    UnityAction.off('NODE_SAVE');
+  }
+  getEditMode() {
+    const { flowDetail, permission } = this.props;
+
+    return 2;
+  }
+  render() {
+    const { flowDetail, permission, currentUser } = this.props;
+    let editMode = 2;
+
+    if (
+      // 判断是否有权限
+      permission['func-01-point-bom-flow'] ||
+      // 判断是否为管理员
+      currentUser.IsSuper
+    ) {
+      editMode = 1;
+    }
+
+    return (
+      <Spin spinning={this.state.spinning}>
+        {/* <Form></Form> */}
+        <Button style={{ marginBottom: 20 }} onClick={() => router.go(-1)}>
+          返回
+        </Button>
+        {currentUser.ID && (
+          <Flow
+            meta={{ type: 'edit', editMode, flowId: 1 }}
+            flowDetail={flowDetail}
+            // onUpdate={node => this.onUpdate(node)}
+          />
+        )}
+      </Spin>
+    );
+  }
+}
+
+export default FlowPage;

+ 661 - 0
src/pages/bom/Flow/FlowDetail.json

@@ -0,0 +1,661 @@
+{
+  "start_node": "41561012",
+  "nodes": [
+    {
+      "id": "41561012",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "BOM-1",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "293a90b5" },
+          { "group": "right", "id": "92334433" },
+          { "group": "bottom", "id": "c2ab5849" },
+          { "group": "left", "id": "6079a903" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -580,
+      "y": -150,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": "139"
+    },
+    {
+      "id": "975bf288",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "方案总审",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "a61170c3" },
+          { "group": "right", "id": "821f59c0" },
+          { "group": "bottom", "id": "17360bc4" },
+          { "group": "left", "id": "15d1b217" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -290,
+      "y": -170,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 5,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "5764f3ce",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "投标清单",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "4b4d9fa6" },
+          { "group": "right", "id": "ce88d7e2" },
+          { "group": "bottom", "id": "e69d8709" },
+          { "group": "left", "id": "c29d7b43" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -138,
+      "y": -150,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": "139"
+    },
+    {
+      "id": "5359e23c",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "三级审批2",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "331cd291" },
+          { "group": "right", "id": "ff6724ee" },
+          { "group": "bottom", "id": "16b4df46" },
+          { "group": "left", "id": "34c9dbc6" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -335,
+      "y": 6,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 9,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "c28a18d3",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "采购执行",
+      "width": 120,
+      "height": 50,
+      "is_seal": 1,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "f71ce55b" },
+          { "group": "right", "id": "e67dc19c" },
+          { "group": "bottom", "id": "a06aba2c" },
+          { "group": "left", "id": "b578cc26" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -138,
+      "y": 26,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "5216c5dc",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "采购合同",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "0fc44196" },
+          { "group": "right", "id": "d2030f1b" },
+          { "group": "bottom", "id": "188c9b68" },
+          { "group": "left", "id": "4e9ce7ad" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -580,
+      "y": 26,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": "147"
+    },
+    {
+      "id": "8c1f18d0",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "预算",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "b58731c5" },
+          { "group": "right", "id": "b3dfbc16" },
+          { "group": "bottom", "id": "89c0bc16" },
+          { "group": "left", "id": "a3adcac9" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -305,
+      "y": -304,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": "148"
+    },
+    {
+      "id": "1aed14d1",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "初版PSR",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "7f8dc65b" },
+          { "group": "right", "id": "9a699e3f" },
+          { "group": "bottom", "id": "d348b56a" },
+          { "group": "left", "id": "47317157" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -138,
+      "y": -304,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "4651130e",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "PSR审批",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "cf1c4df0" },
+          { "group": "right", "id": "1eb352b0" },
+          { "group": "bottom", "id": "83b59198" },
+          { "group": "left", "id": "94f485b5" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 356,
+      "y": -324,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 2,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "a48131e0",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "合同清单",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "3ca1320c" },
+          { "group": "right", "id": "4dee75d9" },
+          { "group": "bottom", "id": "0f72f2ba" },
+          { "group": "left", "id": "bac7962b" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 446,
+      "y": -150,
+      "zIndex": 0,
+      "muti_version": 0,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "b57b57c8",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "终版PSR",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "04c81e99" },
+          { "group": "right", "id": "0d594eef" },
+          { "group": "bottom", "id": "17ff5fe6" },
+          { "group": "left", "id": "73307680" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 621,
+      "y": -150,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "3631eae9",
+      "renderKey": "custom-rect",
+      "name": "custom-rect",
+      "label": "采购清单",
+      "width": 120,
+      "height": 50,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "2aae2a71" },
+          { "group": "right", "id": "e3a42bda" },
+          { "group": "bottom", "id": "0f06668a" },
+          { "group": "left", "id": "8e0bff55" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 446,
+      "y": 26,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 0,
+      "node_type": 0,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "3fb8d302",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "事业部",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "8ab6c3f6" },
+          { "group": "right", "id": "205f1437" },
+          { "group": "bottom", "id": "761ad2b5" },
+          { "group": "left", "id": "22d16375" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 308,
+      "y": -170,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 7,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "399bddb7",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "三级审批1",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "99f69f24" },
+          { "group": "right", "id": "0bccd839" },
+          { "group": "bottom", "id": "42c0d925" },
+          { "group": "left", "id": "58f52f2c" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 173,
+      "y": 6,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 8,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "2427bf29",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "工艺分部经理",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "e5a149c4" },
+          { "group": "right", "id": "e1a1ecea" },
+          { "group": "bottom", "id": "6e131e6a" },
+          { "group": "left", "id": "6bbf9ae4" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -425,
+      "y": -224,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 3,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "be25fe75",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "电气分部经理",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "13e4b9ea" },
+          { "group": "right", "id": "ce651308" },
+          { "group": "bottom", "id": "9a0b8942" },
+          { "group": "left", "id": "a705e7ed" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": -425,
+      "y": -115,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 4,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "node-186a9d31-0bd3-4b36-b61f-6b5380c824db",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "工艺分部经理",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "c6ec15a8-2db4-4ca8-ad81-fd1783b4ca0f" },
+          { "group": "right", "id": "e134d65d-a197-4116-ad74-f47dbbb727d1" },
+          { "group": "bottom", "id": "2c633cdf-7bb5-49ea-a4dc-e3d8c837e513" },
+          { "group": "left", "id": "6d880b9d-7d7e-4357-94dd-caf7d73b5f80" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 27,
+      "y": -224,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 3,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "node-c5171e2d-1cd8-4019-83dc-9f2ed0cab6e8",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "电气分部经理",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "7b9fcd52-4fca-47c7-aaae-e3b117c0c234" },
+          { "group": "right", "id": "6316d87e-2eb3-4ff6-bd8e-0cfd11bff4ce" },
+          { "group": "bottom", "id": "38113945-040f-4374-aca8-38e2e81d71a8" },
+          { "group": "left", "id": "8637b869-7924-416a-b938-30a7ca932901" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 27,
+      "y": -115,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 4,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    },
+    {
+      "id": "node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862",
+      "renderKey": "custom-circle",
+      "name": "custom-circle",
+      "label": "方案总审",
+      "width": 90,
+      "height": 90,
+      "ports": {
+        "items": [
+          { "group": "top", "id": "d9b27b16-08ab-4e0d-84dc-fdec64c0a129" },
+          { "group": "right", "id": "1ab6b2a4-dccd-41e9-83c6-d1642c9ad844" },
+          { "group": "bottom", "id": "b763caac-37c1-4659-ae0e-c7b7c760fec1" },
+          { "group": "left", "id": "2408c946-a670-48b5-a676-d882946b8e36" }
+        ]
+      },
+      "isCustom": true,
+      "parentKey": "1",
+      "x": 173,
+      "y": -170,
+      "zIndex": 0,
+      "muti_version": 1,
+      "flow_id": 5,
+      "node_type": 1,
+      "count": 0,
+      "role_list": ""
+    }
+  ],
+  "edges": [
+    {
+      "id": "975bf288:a61170c3-8c1f18d0:89c0bc16",
+      "source": { "cell": "975bf288", "port": "a61170c3" },
+      "target": { "cell": "8c1f18d0", "port": "89c0bc16" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "8c1f18d0:a3adcac9-41561012:293a90b5",
+      "source": { "cell": "8c1f18d0", "port": "a3adcac9" },
+      "target": { "cell": "41561012", "port": "293a90b5" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "5764f3ce:4b4d9fa6-1aed14d1:d348b56a",
+      "source": { "cell": "5764f3ce", "port": "4b4d9fa6" },
+      "target": { "cell": "1aed14d1", "port": "d348b56a" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":\"5 5\",\"strokeWidth\":1}}"
+    },
+    {
+      "id": "1aed14d1:9a699e3f-4651130e:94f485b5",
+      "source": { "cell": "1aed14d1", "port": "9a699e3f" },
+      "target": { "cell": "4651130e", "port": "94f485b5" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "3fb8d302:205f1437-a48131e0:bac7962b",
+      "source": { "cell": "3fb8d302", "port": "205f1437" },
+      "target": { "cell": "a48131e0", "port": "bac7962b" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "a48131e0:4dee75d9-b57b57c8:73307680",
+      "source": { "cell": "a48131e0", "port": "4dee75d9" },
+      "target": { "cell": "b57b57c8", "port": "73307680" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":\"5 5\",\"strokeWidth\":1}}"
+    },
+    {
+      "id": "a48131e0:0f72f2ba-3631eae9:2aae2a71",
+      "source": { "cell": "a48131e0", "port": "0f72f2ba" },
+      "target": { "cell": "3631eae9", "port": "2aae2a71" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "3631eae9:8e0bff55-399bddb7:0bccd839",
+      "source": { "cell": "3631eae9", "port": "8e0bff55" },
+      "target": { "cell": "399bddb7", "port": "0bccd839" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "399bddb7:58f52f2c-c28a18d3:e67dc19c",
+      "source": { "cell": "399bddb7", "port": "58f52f2c" },
+      "target": { "cell": "c28a18d3", "port": "e67dc19c" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "c28a18d3:b578cc26-5359e23c:ff6724ee",
+      "source": { "cell": "c28a18d3", "port": "b578cc26" },
+      "target": { "cell": "5359e23c", "port": "ff6724ee" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "5359e23c:34c9dbc6-5216c5dc:d2030f1b",
+      "source": { "cell": "5359e23c", "port": "34c9dbc6" },
+      "target": { "cell": "5216c5dc", "port": "d2030f1b" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "b57b57c8:04c81e99-4651130e:1eb352b0",
+      "source": { "cell": "b57b57c8", "port": "04c81e99" },
+      "target": { "cell": "4651130e", "port": "1eb352b0" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "41561012:92334433-2427bf29:6bbf9ae4",
+      "source": { "cell": "41561012", "port": "92334433" },
+      "target": { "cell": "2427bf29", "port": "6bbf9ae4" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "41561012:92334433-be25fe75:a705e7ed",
+      "source": { "cell": "41561012", "port": "92334433" },
+      "target": { "cell": "be25fe75", "port": "a705e7ed" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "2427bf29:e1a1ecea-975bf288:15d1b217",
+      "source": { "cell": "2427bf29", "port": "e1a1ecea" },
+      "target": { "cell": "975bf288", "port": "15d1b217" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "be25fe75:ce651308-975bf288:15d1b217",
+      "source": { "cell": "be25fe75", "port": "ce651308" },
+      "target": { "cell": "975bf288", "port": "15d1b217" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "975bf288:821f59c0-5764f3ce:c29d7b43",
+      "source": { "cell": "975bf288", "port": "821f59c0" },
+      "target": { "cell": "5764f3ce", "port": "c29d7b43" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "5764f3ce:ce88d7e2-node-186a9d31-0bd3-4b36-b61f-6b5380c824db:6d880b9d-7d7e-4357-94dd-caf7d73b5f80",
+      "source": { "cell": "5764f3ce", "port": "ce88d7e2" },
+      "target": {
+        "cell": "node-186a9d31-0bd3-4b36-b61f-6b5380c824db",
+        "port": "6d880b9d-7d7e-4357-94dd-caf7d73b5f80"
+      },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "5764f3ce:ce88d7e2-node-c5171e2d-1cd8-4019-83dc-9f2ed0cab6e8:8637b869-7924-416a-b938-30a7ca932901",
+      "source": { "cell": "5764f3ce", "port": "ce88d7e2" },
+      "target": {
+        "cell": "node-c5171e2d-1cd8-4019-83dc-9f2ed0cab6e8",
+        "port": "8637b869-7924-416a-b938-30a7ca932901"
+      },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "node-186a9d31-0bd3-4b36-b61f-6b5380c824db:e134d65d-a197-4116-ad74-f47dbbb727d1-node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862:2408c946-a670-48b5-a676-d882946b8e36",
+      "source": {
+        "cell": "node-186a9d31-0bd3-4b36-b61f-6b5380c824db",
+        "port": "e134d65d-a197-4116-ad74-f47dbbb727d1"
+      },
+      "target": {
+        "cell": "node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862",
+        "port": "2408c946-a670-48b5-a676-d882946b8e36"
+      },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "node-c5171e2d-1cd8-4019-83dc-9f2ed0cab6e8:6316d87e-2eb3-4ff6-bd8e-0cfd11bff4ce-node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862:2408c946-a670-48b5-a676-d882946b8e36",
+      "source": {
+        "cell": "node-c5171e2d-1cd8-4019-83dc-9f2ed0cab6e8",
+        "port": "6316d87e-2eb3-4ff6-bd8e-0cfd11bff4ce"
+      },
+      "target": {
+        "cell": "node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862",
+        "port": "2408c946-a670-48b5-a676-d882946b8e36"
+      },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862:1ab6b2a4-dccd-41e9-83c6-d1642c9ad844-3fb8d302:22d16375",
+      "source": {
+        "cell": "node-2b3fc359-de49-4f9d-adb5-4eb70b6ba862",
+        "port": "1ab6b2a4-dccd-41e9-83c6-d1642c9ad844"
+      },
+      "target": { "cell": "3fb8d302", "port": "22d16375" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    },
+    {
+      "id": "c28a18d3:a06aba2c-3631eae9:0f06668a",
+      "source": { "cell": "c28a18d3", "port": "a06aba2c" },
+      "target": { "cell": "3631eae9", "port": "0f06668a" },
+      "attr": "{\"line\":{\"stroke\":\"#A2B1C3\",\"targetMarker\":{\"name\":\"block\",\"width\":12,\"height\":8},\"strokeDasharray\":[0,0],\"strokeWidth\":1}}"
+    }
+  ]
+}

+ 53 - 0
src/pages/bom/Flow/FlowModal.js

@@ -0,0 +1,53 @@
+import React, { useEffect } from 'react';
+import { Modal, Input, Table, Select, Form, Radio } from 'antd';
+import FlowDetail from './FlowDetail.json';
+
+const { Option } = Select;
+
+function FlowModal(props) {
+  const { visible, onCancel, onOk, projectList, loading } = props;
+  const [form] = Form.useForm();
+  const formLayout = { labelCol: { span: 4 }, wrapperCol: { span: 14 } };
+
+  const handleOk = async () => {
+    let fieldsValue = await form.validateFields();
+    onOk({
+      ...fieldsValue,
+      ...FlowDetail,
+      project_id: Number(fieldsValue.project_id)
+    });
+  };
+
+  useEffect(() => {
+    if (visible) form.resetFields();
+  }, [visible]);
+
+  return (
+    <Modal
+      confirmLoading={loading}
+      destroyOnClose
+      title="流程"
+      visible={visible}
+      onCancel={onCancel}
+      onOk={handleOk}
+    >
+      <Form {...formLayout} form={form}>
+        <Form.Item label="流程名称" name="name">
+          <Input />
+        </Form.Item>
+        <Form.Item label="所属项目" name="project_id">
+          <Select
+            showSearch
+            filterOption={(input, option) => option.children.join("").toLowerCase().includes(input.toLowerCase())}
+          >
+            {projectList.map(item => (
+              <Option key={item.id}>{item.project_full_code}({item.project_name})</Option>
+            ))}
+          </Select>
+        </Form.Item>
+      </Form>
+    </Modal>
+  );
+}
+
+export default FlowModal;

+ 113 - 0
src/pages/bom/Flow/List.js

@@ -0,0 +1,113 @@
+import React, { useState, useEffect } from 'react';
+import { Form, Select, Button, Table, Input, Checkbox, Divider } from 'antd';
+import { connect } from 'dva';
+import FlowModal from './FlowModal';
+import router from 'umi/router';
+import Link from 'umi/link';
+import { useRequest, useModel } from '@umijs/max';
+
+const { Option } = Select;
+
+function List(props) {
+  const {
+    initialState: { user },
+  } = useModel('@@initialState');
+  const { userList, list, dispatch, projectList, permission, loading } = props;
+  const [visible, setVisible] = useState(false);
+  const columns = [
+    {
+      title: '流程名称',
+      dataIndex: 'Name',
+    },
+    {
+      title: '所属项目',
+      dataIndex: 'ProjectId',
+      render: (projectId) => {
+        let project = projectList.find((item) => item.id == projectId);
+        if (project)
+          return `${project.project_name}(${project.project_full_code})`;
+      },
+    },
+    {
+      title: '操作',
+      render: (item, index) => (
+        <>
+          <a onClick={() => router.push(`/home/flow/${item.Id}`)}>查看</a>
+        </>
+      ),
+    },
+  ];
+
+  const onOk = (values) => {
+    console.log(values);
+    dispatch({
+      type: 'flow/addFlow',
+      payload: values,
+      callback: () => {
+        setVisible(false);
+        dispatch({
+          type: 'flow/queryDefaultBindClassify',
+          payload: {
+            project_id: values.project_id,
+          },
+        });
+      },
+    });
+  };
+
+  useEffect(() => {
+    dispatch({
+      type: 'flow/queryFlowList',
+    });
+    dispatch({
+      type: 'flow/queryProject',
+    });
+    // dispatch({
+    //   type: 'flow/getRoleList',
+    // });
+
+    // dispatch({
+    //   type: 'flow/queryDingTemplateList',
+    // });
+  }, []);
+
+  return (
+    <div>
+      <div style={{ marginBottom: 20 }}>
+        <Button
+          type="primary"
+          style={{ marginRight: 20 }}
+          onClick={() => setVisible(true)}
+        >
+          新增工作流
+        </Button>
+        {(user.Permission['func-01-point-bom-flow'] || user.IsSuper) && (
+          <Link to="/home/audit-list">
+            <Button type="primary">审批流管理</Button>
+          </Link>
+        )}
+      </div>
+
+      <Table
+        rowKey="Id"
+        loading={loading['flow/queryFlowList']}
+        dataSource={list}
+        columns={columns}
+      />
+
+      <FlowModal
+        loading={loading['flow/addFlow']}
+        visible={visible}
+        projectList={projectList}
+        onCancel={() => setVisible(false)}
+        onOk={onOk}
+      />
+    </div>
+  );
+}
+export default connect(({ user, flow, loading }) => ({
+  userList: user.list,
+  list: flow.flowList,
+  projectList: flow.projectList,
+  loading: loading.effects,
+}))(List);

+ 5 - 0
src/pages/bom/Flow/index.less

@@ -0,0 +1,5 @@
+body {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}

+ 294 - 0
src/pages/bom/Flow/models/flow.js

@@ -0,0 +1,294 @@
+import {
+  queryAuditList,
+  addAudit,
+  addAuditNode,
+  addFlow,
+  queryBoomFlowDetail,
+  updateNode,
+  queryFlowList,
+  queryDingTemplateList,
+  saveAuditFlowInfo,
+  queryDepV2,
+  queryProcessFlows,
+  queryDefaultBindClassify,
+} from '@/services/boom';
+import { queryApproval } from '@/services/approval';
+import { queryRole } from '@/services/SysAdmin';
+// import { queryProject } from '@/services/PurchaseList';
+import { message } from 'antd';
+
+function getDepUserTree(data) {
+  data.title = `${data.Name}`;
+  data.id = data.ID;
+  data.value = data.ID;
+  // data.selectable = false;
+  if (!data.children) data.children = new Array();
+
+  if (data.children) {
+    data.children.forEach((item) => {
+      getDepUserTree(item);
+    });
+  }
+
+  if (data.Users && data.Users.length !== 0) {
+    data.Users.forEach((item) => {
+      item.title = item.CName;
+      item.id = item.ID + '||' + data.ID;
+      item.value = item.ID + '||' + data.ID;
+      // item.selectable = true;
+      item.DepId = data.ID;
+      data.children.push(item);
+    });
+  }
+  return data;
+}
+
+const getFlowDetail = (data) => {
+  const groups = {
+    top: {
+      position: { name: 'top' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    right: {
+      position: { name: 'right' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    bottom: {
+      position: { name: 'bottom' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    left: {
+      position: { name: 'left' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+  };
+  const attrs = {
+    line: {
+      stroke: '#A2B1C3',
+      targetMarker: { name: 'block', width: 12, height: 8 },
+      strokeDasharray: '5 5',
+      strokeWidth: 1,
+    },
+  };
+  let nodes = data.nodes.map((item) => {
+    let node = { ...item };
+    node.ports.groups = groups;
+    node.parentKey = '1';
+
+    return node;
+  });
+  let edges = data.edges.map((item) => {
+    let edge = { ...item };
+    try {
+      edge.attrs = item.attr ? JSON.parse(item.attr) : attrs;
+    } catch (error) {
+      edge.attrs = attrs;
+    }
+    return edge;
+  });
+  return {
+    ...data,
+    nodes,
+    edges,
+  };
+};
+
+export default {
+  namespace: 'flow',
+  state: {
+    flowDetail: { nodes: [], edges: [] },
+    formData: {},
+    auditList: [],
+    flowList: [],
+    projectList: [],
+    current: {},
+    roleList: [],
+    templateList: [],
+    depUserTree: [],
+    simpleFlowDteail: '',
+  },
+
+  effects: {
+    *addFlow({ payload, callback }, { call, put }) {
+      const res = yield call(addFlow, payload);
+      if (res) {
+        message.success('添加成功');
+        callback && callback();
+        yield put({
+          type: 'queryFlowList',
+        });
+      }
+    },
+    *getRoleList({ payload }, { call, put }) {
+      const response = yield call(queryRole, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { roleList: response.data.list },
+        });
+      }
+    },
+    *queryBoomFlowDetail({ payload }, { call, put }) {
+      const data = yield call(queryBoomFlowDetail, payload);
+      console.log(data);
+      yield put({
+        type: 'save',
+        payload: { flowDetail: data },
+      });
+    },
+    *queryProject({ callback }, { call, put }) {
+      const response = yield call(queryApproval, { pageSize: 99999 });
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: {
+            projectList: response.data.list,
+          },
+        });
+      }
+    },
+    *queryFlowList({ payload }, { call, put }) {
+      const res = yield call(queryFlowList, payload);
+      yield put({
+        type: 'save',
+        payload: { flowList: res.data },
+      });
+    },
+    *updateNode({ payload, callback }, { call, put }) {
+      const data = yield call(updateNode, payload);
+      console.log(data);
+      message.success('修改成功');
+      callback && callback();
+    },
+    *queryAuditList({ payload }, { call, put }) {
+      const response = yield call(queryAuditList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { auditList: response.data },
+        });
+      }
+    },
+    *addAudit({ payload, callback }, { call, put }) {
+      const response = yield call(addAudit, payload);
+      if (response) {
+        message.success('新增成功');
+        callback && callback();
+        yield put({
+          type: 'queryAuditList',
+          payload: {},
+        });
+      }
+    },
+    *addAuditNode({ payload, callback }, { call, put }) {
+      const response = yield call(addAuditNode, payload);
+      if (response) {
+        message.success('操作成功');
+        callback && callback();
+      }
+    },
+    *queryDingTemplateList({ payload }, { call, put }) {
+      const response = yield call(queryDingTemplateList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { templateList: response.data.result },
+        });
+      }
+    },
+    *saveAuditFlowInfo({ payload, callback }, { call, put }) {
+      const response = yield call(saveAuditFlowInfo, payload);
+      if (response) {
+        message.success('保存成功');
+        callback && callback();
+
+        yield put({
+          type: 'queryProcessFlows',
+          payload: { ids: payload.id },
+        });
+      }
+    },
+    *fetchDepV2({ payload, callback }, { call, put }) {
+      const response = yield call(queryDepV2, { pageSize: 999999 });
+      if (response) {
+        // const depUserTree = response.data?.list;
+        const depUserTree = response.data.list.map((item) => {
+          return getDepUserTree(item);
+        });
+        yield put({
+          type: 'save',
+          payload: { depUserTree },
+        });
+      }
+    },
+    *queryProcessFlows({ payload }, { call, put }) {
+      const data = yield call(queryProcessFlows, payload);
+      if (data && data.length > 0) {
+        yield put({
+          type: 'save',
+          payload: {
+            flowDetail: data[0].process_json
+              ? getFlowDetail(JSON.parse(data[0].process_json))
+              : { nodes: [], edges: [] },
+            formData: data[0].form_json ? JSON.parse(data[0].form_json) : [],
+            simpleFlowDteail: data[0].process_simple_json,
+          },
+        });
+      }
+    },
+    *queryDefaultBindClassify({ payload }, { call, put }) {
+      const data = yield call(queryDefaultBindClassify, payload);
+      if (data) {
+      }
+    },
+  },
+
+  reducers: {
+    save(state, action) {
+      return {
+        ...state,
+        ...action.payload,
+      };
+    },
+  },
+};

+ 416 - 394
src/services/boom.js

@@ -245,423 +245,445 @@ export async function queryFlowDelete(id) {
   return request(`/api/v1/oa/flow/delete/${id}`);
 }
 
-// /**
-//   project_id
-//   version_id	大版本id
-//   template_id
-//   template_node_id	查询某流程和某节点下最新版本的数据记录
-//   node_id	查询某审批流程和某审批节点下最新版本的数据记录
-//  */
-// export async function queryRecord(params) {
-//   return request(`/api/v1/purchase/record?${stringify(params)}`);
-// }
-// //删除excel中单个sheet页
-// export async function queryDelSheetRecord(params) {
-//   const response = await request(`/api/v1/purchase/bom/del-purchase-excel-sheet?${stringify(params)}`);
-//   if (response.code == 200) {
-//     // message.success('删除成功');
-//   }
-// }
+/**
+  project_id
+  version_id	大版本id
+  template_id
+  template_node_id	查询某流程和某节点下最新版本的数据记录
+  node_id	查询某审批流程和某审批节点下最新版本的数据记录
+ */
+export async function queryRecord(params) {
+  return request(`/api/v1/purchase/record?${stringify(params)}`);
+}
+//删除excel中单个sheet页
+export async function queryDelSheetRecord(params) {
+  const response = await request(
+    `/api/v1/purchase/bom/del-purchase-excel-sheet?${stringify(params)}`,
+  );
+  if (response.code == 200) {
+    // message.success('删除成功');
+  }
+}
 
-// // 查询全部工作流
-// export async function queryFlowList(params) {
-//   return request(`/api/v1/purchase/bom/flows?${stringify(params)}`);
-// }
+// 查询全部工作流
+export async function queryFlowList(params) {
+  return request(`/api/v1/purchase/bom/flows?${stringify(params)}`);
+}
 
-// // 根据节点id查询所有version
-// export async function queryVserionByNode(params, signal) {
-//   return request(`/api/v1/purchase/bom/flow/node?${stringify(params)}`, {
-//     signal,
-//   });
-// }
+// 根据节点id查询所有version
+export async function queryVserionByNode(params, signal) {
+  return request(`/api/v1/purchase/bom/flow/node?${stringify(params)}`, {
+    signal,
+  });
+}
 
-// export async function commitSheet(params) {
-//   return request(`/api/v1/purchase/record`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
-// export async function approve(params) {
-//   return request(`/api/v1/purchase/audit/status`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
-// export async function queryAuthority(params) {
-//   const depId = localStorage.depId;
-//   return request(`/api/v1/purchase/bom/user/excel/col?depId=${depId}`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
-// export async function addBomComment(params) {
-//   return request(`/api/v1/purchase/comment`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
-// export async function queryBomComment(params) {
-//   return request(`/api/v1/purchase/comment?${stringify(params)}`);
-// }
+export async function commitSheet(params) {
+  return request(`/api/v1/purchase/record`, {
+    method: 'POST',
+    data: params,
+  });
+}
+export async function approve(params) {
+  return request(`/api/v1/purchase/audit/status`, {
+    method: 'POST',
+    data: params,
+  });
+}
+export async function queryAuthority(params) {
+  const depId = localStorage.depId;
+  return request(`/api/v1/purchase/bom/user/excel/col?depId=${depId}`, {
+    method: 'POST',
+    data: params,
+  });
+}
+export async function addBomComment(params) {
+  return request(`/api/v1/purchase/comment`, {
+    method: 'POST',
+    data: params,
+  });
+}
+export async function queryBomComment(params) {
+  return request(`/api/v1/purchase/comment?${stringify(params)}`);
+}
 
-// /**
-//  * 提交流转
-//   "id":3, 当前流转文档id,必填
-//   "project_id":46, 所属项目id
-//   "template_id":1, 所属模板id ,必填
-//   "template_node_id":34,所属节点id,必填
-//   "next_template_id":1,跳转的下级业务模板id,必填
-//   "next_template_node_id":2,跳转的下级业务节点id,必填
-//   "flow_id":1, 跳转的下级审核流程id , 如果不为空,则说明流转的是审核节点,下级业务节点为审核通过后进入的业务节点
-//   "node_id":1,跳转的下级审核节点id
-//   "desc":"流转描述"
-//  */
-// export async function submitNextNode(params) {
-//   return request(`/api/v1/purchase/next/node/submit`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
+/**
+ * 提交流转
+  "id":3, 当前流转文档id,必填
+  "project_id":46, 所属项目id
+  "template_id":1, 所属模板id ,必填
+  "template_node_id":34,所属节点id,必填
+  "next_template_id":1,跳转的下级业务模板id,必填
+  "next_template_node_id":2,跳转的下级业务节点id,必填
+  "flow_id":1, 跳转的下级审核流程id , 如果不为空,则说明流转的是审核节点,下级业务节点为审核通过后进入的业务节点
+  "node_id":1,跳转的下级审核节点id
+  "desc":"流转描述"
+ */
+export async function submitNextNode(params) {
+  return request(`/api/v1/purchase/next/node/submit`, {
+    method: 'POST',
+    data: params,
+  });
+}
 // export async function advanceSubmitNextNode(params) {
 //   return request(`/api/v1/purchase/next/node/advance-submit`, {
 //     method: 'POST',
-//     body: params,
+//     data: params,
 //   });
 // }
 
-// export async function queryDetail(params) {
-//   let response = await request(`/api/v1/purchase/record?${stringify(params)}`);
-//   let sheet = response.data;
-//   sheet.data = JSON.parse(sheet.data || '[]');
-//   sheet.data.forEach(item => {
-//     item.config = JSON.parse(item.config || '{}');
-//     item.celldata = JSON.parse(item.cell_data || '[]');
-//     delete item.cell_data;
-//   });
-//   return sheet;
-// }
-// export async function queryHistoryDetail(params) {
-//   return request(`/api/v1/purchase/record/history/detail?${stringify(params)}`);
-// }
-// export async function queryHistoryList(params) {
-//   return request(`/api/v1/purchase/record/history?${stringify(params)}`);
-// }
+export async function queryDetail(params) {
+  let response = await request(`/api/v1/purchase/record?${stringify(params)}`);
+  let sheet = response.data;
+  sheet.data = JSON.parse(sheet.data || '[]');
+  sheet.data.forEach((item) => {
+    item.config = JSON.parse(item.config || '{}');
+    item.celldata = JSON.parse(item.cell_data || '[]');
+    delete item.cell_data;
+  });
+  return sheet;
+}
+export async function queryHistoryDetail(params) {
+  return request(`/api/v1/purchase/record/history/detail?${stringify(params)}`);
+}
+export async function queryHistoryList(params) {
+  return request(`/api/v1/purchase/record/history?${stringify(params)}`);
+}
 
-// export async function queryBoomFlowList(params) {
-//   return request(`/api/v1/purchase/bom/flows?${stringify(params)}`);
-// }
-// //请求历史版本
-// export async function queryVersionsTree(params) {
-//   return request(`/api/v1/purchase/record/version/tree?${stringify(params)}`);
-// }
-// //查询业务节点的审核记录
-// export async function queryAuditExcel(params) {
-//   return request(`/api/v1/purchase/audit/excel?${stringify(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) {
-//   let res = await request(`/api/v1/purchase/bom/ding/instance-detail`, {
-//     method: 'POST',
-//     body: params,
-//   });
-//   if (res.data.errcode != 0) {
-//     message.error(res.data.errmsg);
-//     throw new Error(res.data.errmsg);
-//   }
-//   return res;
-// }
-// export async function queryDingInstanceExecute(params) {
-//   let res = await request(`/api/v1/purchase/bom/ding/instance-execute`, {
-//     method: 'POST',
-//     body: params,
-//   });
-//   if (res.data.errcode != 0) {
-//     message.error('审批失败,请联系管理员。');
-//     throw new Error(res.data.errmsg);
-//   }
-//   return res;
-// }
-// export async function queryListParentByUser(params) {
-//   return request(`/api/v1/purchase/bom/ding/department/list-parent-by-user`, {
-//     method: 'POST',
-//     body: params,
-//   });
-// }
-// /**
-//  * 查看项目流程列表
-//  * project_id
-//  */
-// export async function queryProjectRecord(params) {
-//   return request(`/api/v1/purchase/bom/project/record?${stringify(params)}`);
-// }
-// /** 查看版本列表
-//  *  project_id
-//     template_id		流程id
-//     template_node_id	流程节点id
-//  */
-// export async function queryVersionsList(params) {
-//   return request(`/api/v1/purchase/record/versions?${stringify(params)}`);
-// }
+export async function queryBoomFlowList(params) {
+  return request(`/api/v1/purchase/bom/flows?${stringify(params)}`);
+}
+//请求历史版本
+export async function queryVersionsTree(params) {
+  return request(`/api/v1/purchase/record/version/tree?${stringify(params)}`);
+}
+//查询业务节点的审核记录
+export async function queryAuditExcel(params) {
+  return request(`/api/v1/purchase/audit/excel?${stringify(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) {
+  let res = await request(`/api/v1/purchase/bom/ding/instance-detail`, {
+    method: 'POST',
+    data: params,
+  });
+  if (res.data.errcode != 0) {
+    message.error(res.data.errmsg);
+    throw new Error(res.data.errmsg);
+  }
+  return res;
+}
+export async function queryDingInstanceExecute(params) {
+  let res = await request(`/api/v1/purchase/bom/ding/instance-execute`, {
+    method: 'POST',
+    data: params,
+  });
+  if (res.data.errcode != 0) {
+    message.error('审批失败,请联系管理员。');
+    throw new Error(res.data.errmsg);
+  }
+  return res;
+}
+export async function queryListParentByUser(params) {
+  return request(`/api/v1/purchase/bom/ding/department/list-parent-by-user`, {
+    method: 'POST',
+    data: params,
+  });
+}
+/**
+ * 查看项目流程列表
+ * project_id
+ */
+export async function queryProjectRecord(params) {
+  return request(`/api/v1/purchase/bom/project/record?${stringify(params)}`);
+}
+/** 查看版本列表
+ *  project_id
+    template_id		流程id
+    template_node_id	流程节点id
+ */
+export async function queryVersionsList(params) {
+  return request(`/api/v1/purchase/record/versions?${stringify(params)}`);
+}
 
-// export async function queryBoomFlowDetail(params) {
-//   let { data } = await request(`/api/v1/purchase/bom/flow/info?${stringify(params)}`);
-//   const groups = {
-//     top: {
-//       position: { name: 'top' },
-//       attrs: {
-//         circle: {
-//           r: 4,
-//           magnet: true,
-//           stroke: '#31d0c6',
-//           strokeWidth: 2,
-//           fill: '#fff',
-//           style: { visibility: 'hidden' },
-//         },
-//       },
-//       zIndex: 10,
-//     },
-//     right: {
-//       position: { name: 'right' },
-//       attrs: {
-//         circle: {
-//           r: 4,
-//           magnet: true,
-//           stroke: '#31d0c6',
-//           strokeWidth: 2,
-//           fill: '#fff',
-//           style: { visibility: 'hidden' },
-//         },
-//       },
-//       zIndex: 10,
-//     },
-//     bottom: {
-//       position: { name: 'bottom' },
-//       attrs: {
-//         circle: {
-//           r: 4,
-//           magnet: true,
-//           stroke: '#31d0c6',
-//           strokeWidth: 2,
-//           fill: '#fff',
-//           style: { visibility: 'hidden' },
-//         },
-//       },
-//       zIndex: 10,
-//     },
-//     left: {
-//       position: { name: 'left' },
-//       attrs: {
-//         circle: {
-//           r: 4,
-//           magnet: true,
-//           stroke: '#31d0c6',
-//           strokeWidth: 2,
-//           fill: '#fff',
-//           style: { visibility: 'hidden' },
-//         },
-//       },
-//       zIndex: 10,
-//     },
-//   };
-//   const attrs = {
-//     line: {
-//       stroke: '#A2B1C3',
-//       targetMarker: { name: 'block', width: 12, height: 8 },
-//       strokeDasharray: '5 5',
-//       strokeWidth: 1,
-//     },
-//   };
-//   let nodes = data.Nodes.map(item => {
-//     let node = {
-//       ...item,
-//       id: item.node_id,
-//       renderKey: item.render_key,
-//       zIndex: item.z_index,
-//       isCustom: !!item.is_custom,
-//       ports: JSON.parse(item.ports || '{}'),
-//     };
-//     node.ports.groups = groups;
-//     node.parentKey = '1';
-
-//     return node;
-//   });
-//   let edges = data.Edges.map(item => {
-//     let edge = {
-//       id: item.edge_id,
-//       source: {
-//         cell: item.source_cell,
-//         port: item.source_port,
-//       },
-//       target: {
-//         cell: item.target_cell,
-//         port: item.target_port,
-//       },
-//     };
-//     try {
-//       edge.attrs = item.attr ? JSON.parse(item.attr) : attrs;
-//     } catch (error) {
-//       edge.attrs = attrs;
-//     }
-//     return edge;
-//   });
-//   return {
-//     ...data,
-//     nodes,
-//     edges,
-//   };
-// }
-// export async function updateNode(data) {
-//   return request(`/api/v1/purchase/bom/flow/${data.templateId}/${data.nodeId}`, {
-//     method: 'PUT',
-//     body: data.body,
-//   });
-// }
-// export async function addBoomFlow(data) {
-//   return request(`/api/v1/purchase/bom/flow/info`, {
-//     method: 'POST',
-//     body: data,
-//   });
-// }
+export async function queryBoomFlowDetail(params) {
+  let { data } = await request(
+    `/api/v1/purchase/bom/flow/info?${stringify(params)}`,
+  );
+  const groups = {
+    top: {
+      position: { name: 'top' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    right: {
+      position: { name: 'right' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    bottom: {
+      position: { name: 'bottom' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+    left: {
+      position: { name: 'left' },
+      attrs: {
+        circle: {
+          r: 4,
+          magnet: true,
+          stroke: '#31d0c6',
+          strokeWidth: 2,
+          fill: '#fff',
+          style: { visibility: 'hidden' },
+        },
+      },
+      zIndex: 10,
+    },
+  };
+  const attrs = {
+    line: {
+      stroke: '#A2B1C3',
+      targetMarker: { name: 'block', width: 12, height: 8 },
+      strokeDasharray: '5 5',
+      strokeWidth: 1,
+    },
+  };
+  let nodes = data.Nodes.map((item) => {
+    let node = {
+      ...item,
+      id: item.node_id,
+      renderKey: item.render_key,
+      zIndex: item.z_index,
+      isCustom: !!item.is_custom,
+      ports: JSON.parse(item.ports || '{}'),
+    };
+    node.ports.groups = groups;
+    node.parentKey = '1';
 
-// export async function addFlow(data) {
-//   return request(`/api/v1/purchase/bom/flow/info`, {
-//     method: 'POST',
-//     body: data,
-//   });
-// }
-// /**
-//  *  [
-//       {
-//         "flow_id": 23,
-//         "node": "主管",
-//         "desc": "desc",
-//         "auditor": 2,
-//         "seq": 1,
-//         "seq_relate": 0
-//       }
-//     ]
-//  */
-// export async function addAuditNode(data) {
-//   return request(`/api/v1/purchase/flow/info/${data.flowId}`, {
-//     method: 'POST',
-//     body: data.nodes,
-//   });
-// }
+    return node;
+  });
+  let edges = data.Edges.map((item) => {
+    let edge = {
+      id: item.edge_id,
+      source: {
+        cell: item.source_cell,
+        port: item.source_port,
+      },
+      target: {
+        cell: item.target_cell,
+        port: item.target_port,
+      },
+    };
+    try {
+      edge.attrs = item.attr ? JSON.parse(item.attr) : attrs;
+    } catch (error) {
+      edge.attrs = attrs;
+    }
+    return edge;
+  });
+  return {
+    ...data,
+    nodes,
+    edges,
+  };
+}
+export async function updateNode(data) {
+  return request(
+    `/api/v1/purchase/bom/flow/${data.templateId}/${data.nodeId}`,
+    {
+      method: 'PUT',
+      data: data.body,
+    },
+  );
+}
+export async function addBoomFlow(data) {
+  return request(`/api/v1/purchase/bom/flow/info`, {
+    method: 'POST',
+    data,
+  });
+}
 
-// export async function queryRecordSheet(data) {
-//   return request(`/api/v1/purchase/record/sheet?${stringify(data)}`, {
-//     method: 'POST',
-//     body: data,
-//   });
-// }
-// export async function queryDingTemplateList() {
-//   return request(`/api/v1/purchase/bom/ding/template/list`);
-// }
+export async function addFlow(data) {
+  return request(`/api/v1/purchase/bom/flow/info`, {
+    method: 'POST',
+    data,
+  });
+}
+/**
+ *  [
+      {
+        "flow_id": 23,
+        "node": "主管",
+        "desc": "desc",
+        "auditor": 2,
+        "seq": 1,
+        "seq_relate": 0
+      }
+    ]
+ */
+export async function addAuditNode(data) {
+  return request(`/api/v1/purchase/flow/info/${data.flowId}`, {
+    method: 'POST',
+    data: data.nodes,
+  });
+}
 
-// 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 queryRecordSheet(data) {
+  return request(`/api/v1/purchase/record/sheet?${stringify(data)}`, {
+    method: 'POST',
+    data,
+  });
+}
+export async function queryDingTemplateList() {
+  return request(`/api/v1/purchase/bom/ding/template/list`);
+}
 
-// 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;
-// }
+export async function queryDDdepList(data) {
+  let res = await request(`/api/v1/purchase/bom/ding/department-list`, {
+    method: 'POST',
+    data,
+  });
+  return res.data.result;
+}
 
-// export async function uploadFile(data) {
-//   let res = await request(`/api/v1/purchase/bom/ding/upload-file`, {
-//     method: 'POST',
-//     body: data,
-//     headers: {
-//       ContentType: 'application/x-www-form-urlencoded',
-//     },
-//   });
-//   if (!res.data.dentry) {
-//     message.error(res.data.errmsg);
-//     throw new Error(res.data.errmsg);
-//   }
-//   return res.data;
-// }
+export async function queryDDProcessesForecast(data) {
+  let res = await request(`/api/v1/purchase/bom/ding/processes-forecast`, {
+    method: 'POST',
+    data,
+  });
+  if (res.data.message) {
+    // message.error(res.data.message);
+    throw new Error(res.data.message);
+  }
+  return res.data.result;
+}
 
-// export async function bindDDCode(userId, code) {
-//   let res = await request(`/api/v1/purchase/bom/ding/set-ding-user-code?ucode=${userId}:${code}`, {
-//     method: 'GET',
-//   });
+export async function uploadFile(data) {
+  let res = await request(`/api/v1/purchase/bom/ding/upload-file`, {
+    method: 'POST',
+    data,
+    headers: {
+      ContentType: 'application/x-www-form-urlencoded',
+    },
+  });
+  if (!res.data.dentry) {
+    message.error(res.data.errmsg);
+    throw new Error(res.data.errmsg);
+  }
+  return res.data;
+}
 
-//   return res.data;
-// }
+export async function bindDDCode(userId, code) {
+  let res = await request(
+    `/api/v1/purchase/bom/ding/set-ding-user-code?ucode=${userId}:${code}`,
+    {
+      method: 'GET',
+    },
+  );
 
-// //获取部门结构
-// export async function queryDepV2(params) {
-//   return request(`/api/v2/dep?${stringify(params)}`);
-// }
+  return res.data;
+}
 
-// //新增工作流时调用接口 给项目绑定默认分类列表
-// //purchase/bom/default-bind-classify?project_id=1
-// export async function queryDefaultBindClassify(params) {
-//   let res = await request(`/api/v1/purchase/bom/default-bind-classify?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res.data;
-// }
+//获取部门结构
+export async function queryDepV2(params) {
+  return request(`/api/v2/dep?${stringify(params)}`);
+}
 
-// export async function queryBindClassify(params) {
-//   let res = await request(`/api/v1/purchase/bom/get-bind-classify?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res.data;
-// }
+//新增工作流时调用接口 给项目绑定默认分类列表
+//purchase/bom/default-bind-classify?project_id=1
+export async function queryDefaultBindClassify(params) {
+  let res = await request(
+    `/api/v1/purchase/bom/default-bind-classify?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res.data;
+}
 
-// export async function queryAddBindClassify(data) {
-//   return request(`/api/v1/purchase/bom/add-bind-classify`, {
-//     method: 'POST',
-//     body: data,
-//   });
-// }
+export async function queryBindClassify(params) {
+  let res = await request(
+    `/api/v1/purchase/bom/get-bind-classify?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res.data;
+}
 
-// export async function queryDelPurchaseExcel(params) {
-//   let res = await request(`/api/v1/purchase/bom/del-purchase-excel?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res;
-// }
-// //提交流转存储表单审批人历史记录
-// export async function querySaveBomForm(data) {
-//   return request(`/api/v1/purchase/bom/save-bom-form`, {
-//     method: 'POST',
-//     body: data,
-//   });
-// }
+export async function queryAddBindClassify(data) {
+  return request(`/api/v1/purchase/bom/add-bind-classify`, {
+    method: 'POST',
+    data,
+  });
+}
 
-// //章管家失败,重新申请用印
-// export async function queryTrySeal(params) {
-//   let res = await request(`/api/v1/purchase/bom/try-seal?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res;
-// }
+export async function queryDelPurchaseExcel(params) {
+  let res = await request(
+    `/api/v1/purchase/bom/del-purchase-excel?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res;
+}
+//提交流转存储表单审批人历史记录
+export async function querySaveBomForm(data) {
+  return request(`/api/v1/purchase/bom/save-bom-form`, {
+    method: 'POST',
+    data,
+  });
+}
 
-// export async function ChartTempOSSData(params) {
-//   return request(`/api/v1/purchase/bom/contract-file/${params.projectId}`);
-// }
-// // 设置最终版本
-// export async function setLastVersion(excelId) {
-//   return request(`/api/v1/purchase/bom/set-last-version/${excelId}`);
-// }
+//章管家失败,重新申请用印
+export async function queryTrySeal(params) {
+  let res = await request(
+    `/api/v1/purchase/bom/try-seal?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res;
+}
+
+export async function ChartTempOSSData(params) {
+  return request(`/api/v1/purchase/bom/contract-file/${params.projectId}`);
+}
+// 设置最终版本
+export async function setLastVersion(excelId) {
+  return request(`/api/v1/purchase/bom/set-last-version/${excelId}`);
+}