Renxy 2 жил өмнө
parent
commit
35943f96cb

+ 0 - 56
src/components/Flow/components/departSelect/index.tsx

@@ -1,56 +0,0 @@
-import { TreeSelect, TreeSelectProps } from 'antd';
-import React, { useState, useEffect } from 'react';
-import { queryDDdepList } from '@/services/boom';
-
-function DepartmentSelect(props) {
-  const { value, defaultValue, 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: TreeSelectProps['loadData'] = async ({ id }) => {
-    let depList = await queryDDdepList({ dept_id: id });
-
-    console.log(depList);
-    if (depList.length > 0) {
-      let nodes = depList.map(genTreeNode);
-      setTreeData([...treeData, ...nodes]);
-    }
-  };
-
-  useEffect(() => {
-    onLoadData({});
-  }, []);
-
-  return (
-    <TreeSelect
-      treeDataSimpleMode
-      multiple
-      style={{
-        width: '100%',
-      }}
-      defaultValue={defaultValue}
-      // value={value}
-      dropdownStyle={{
-        maxHeight: 400,
-        overflow: 'auto',
-      }}
-      placeholder="请选择部门"
-      onChange={onChange}
-      loadData={onLoadData}
-      treeData={treeData}
-    />
-  );
-}
-
-export default DepartmentSelect;

+ 139 - 25
src/components/Flow/components/judgeComponent/index.tsx

@@ -1,14 +1,24 @@
-import React, { useEffect, useState } from 'react';
-import { Checkbox, Select } from 'antd';
-import DepartmentSelect from '../departSelect';
+import React, { useEffect, useMemo, useState } from 'react';
+import { Checkbox, Select, TreeSelect } from 'antd';
+import { DeleteOutlined } from '@ant-design/icons';
 import { ComponentName, FormItem } from '../../node/judgeNode/mapServe';
 import { InputNumberFiled } from '../../node/fields';
+import { connect } from 'dva';
+
+const { Option } = Select;
+
+interface Condition {
+  smallValue?: number;
+  smallSign?: number;
+  bigValue?: number;
+  bigSign?: number;
+}
 
 export interface JudgeType {
   type: string;
   id: string;
-  condition?: number;
-  values?: string[] | number[];
+  condition?: Condition;
+  values?: any[];
 }
 
 export const JudgeOptions = [
@@ -21,10 +31,11 @@ export const JudgeOptions = [
 ];
 
 const RenderJudge = (props: any) => {
-  const { formItems = '', onChange } = props;
+  const { formItems = '', onChange, depUserTree } = props;
   let formData: FormItem[] = formItems ? JSON.parse(formItems) : [];
 
-  const handleChange = (values: string[] | number[], item: FormItem, condition?: number) => {
+  const [isBetween, setIsBetween] = useState(false);
+  const handleChange = (values: any[], item: FormItem, condition?: Condition) => {
     const itemCur = formData.find(cur => cur.props.id == item.props.id);
     let judge: JudgeType = {
       id: item.props.id,
@@ -47,40 +58,140 @@ const RenderJudge = (props: any) => {
     onChange(formData);
   };
 
+  const getTreeNode = (pid, dep) => {
+    return {
+      id: dep.ID,
+      pId: pid,
+      value: dep.ID,
+      title: dep.Name,
+      isLeaf: false,
+    };
+  };
+  const getResult = (pid, items) => {
+    let result = [];
+    items.forEach(item => {
+      let node = getTreeNode(pid, item);
+      result.push(node);
+      if (item.children) {
+        let node = getResult(item.ID, item.children);
+        result = [...result, ...node];
+      }
+    });
+    return result;
+  };
+
+  const handleDelete = (item: FormItem) => {
+    const index = formData.findIndex(cur => cur.props.id == item.props.id);
+    if (index != -1) {
+      formData.splice(index, 1);
+      onChange(formData);
+    }
+  };
+
+  const handleTreeChange = (values: (string | number)[], item: FormItem) => {
+    const newValues = values.map(cur => {
+      if (typeof cur == 'string' && cur.includes('||')) {
+        return { type: 'user', value: Number(cur.split('||')[0]), origin: cur };
+      } else {
+        return { type: 'dep', value: cur, origin: cur };
+      }
+    });
+    console.log('=====================', newValues);
+    handleChange(newValues, item);
+  };
+
   const RenderComp = (item: FormItem) => {
     let component;
     switch (item.componentName) {
       case ComponentName.Inner:
         component = (
-          <div className="group">
-            <div>发起人</div>
-            <DepartmentSelect
-              defaultValue={item.judge?.values}
-              onChange={values => handleChange(values, item)}
+          <>
+            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+              <div>发起人</div>
+              <DeleteOutlined onClick={() => handleDelete(item)} />
+            </div>
+            <TreeSelect
+              showSearch
+              multiple
+              allowClear
+              defaultValue={item.judge?.values?.map(item => item.origin)}
+              style={{ width: '100%' }}
+              placeholder="请选择部门"
+              treeData={depUserTree}
+              onChange={values => {
+                handleTreeChange(values, item);
+                // handleChange(values, item)
+              }}
             />
-          </div>
+          </>
         );
         break;
       case ComponentName.Depart:
         break;
       case ComponentName.Money:
-        console.log(item);
+      case ComponentName.Number:
+        const { judge, props } = item;
         component = (
           <>
-            <div>{item.props.label}</div>
+            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+              <div>{props.label}</div>
+              <DeleteOutlined onClick={() => handleDelete(item)} />
+            </div>
             <Select
               options={JudgeOptions}
-              defaultValue={item.judge?.values[0] || 1}
+              defaultValue={judge?.values[0]}
               onChange={(value: number) => {
-                handleChange([value], item);
-              }}
-            />
-            <InputNumberFiled
-              value={item.judge?.condition}
-              onChange={value => {
-                handleChange([], item, value);
+                let newCondition: Condition = null;
+                value == 6 ? setIsBetween(true) : setIsBetween(false);
+                if (judge && judge.values && judge.values.length > 0) {
+                  if (judge?.values[0] == 6 && value != 6) newCondition = {};
+                  else if (judge.values[0] != 6 && value == 6) newCondition = {};
+                }
+                handleChange([value], item, newCondition);
               }}
             />
+            {isBetween ? (
+              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+                <InputNumberFiled
+                  value={judge?.condition?.smallValue}
+                  onChange={value => {
+                    handleChange([], item, { ...judge?.condition, smallValue: value });
+                  }}
+                />
+                <Select
+                  defaultValue={judge?.condition?.smallSign}
+                  onChange={(value: number) => {
+                    handleChange([], item, { ...judge?.condition, smallSign: value });
+                  }}
+                >
+                  <Option value={1}>{`<`}</Option>
+                  <Option value={2}>≤</Option>
+                </Select>
+                <span>N</span>
+                <InputNumberFiled
+                  value={judge?.condition?.bigValue}
+                  onChange={value => {
+                    handleChange([], item, { ...judge?.condition, bigValue: value });
+                  }}
+                />
+                <Select
+                  defaultValue={judge?.condition?.bigSign}
+                  onChange={(value: number) => {
+                    handleChange([], item, { ...judge?.condition, bigSign: value });
+                  }}
+                >
+                  <Option value={1}>{`<`}</Option>
+                  <Option value={2}>≤</Option>
+                </Select>
+              </div>
+            ) : (
+              <InputNumberFiled
+                value={judge?.condition?.smallValue}
+                onChange={value => {
+                  handleChange([], item, { smallValue: value });
+                }}
+              />
+            )}
           </>
         );
         break;
@@ -90,7 +201,10 @@ const RenderJudge = (props: any) => {
         const options = item.props.options;
         component = (
           <>
-            <div>{item.props.label}</div>
+            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+              <div>{item.props.label}</div>
+              <DeleteOutlined onClick={() => handleDelete(item)} />
+            </div>
             <Checkbox.Group
               defaultValue={item.judge?.values}
               onChange={(values: any) => handleChange(values, item)}
@@ -113,4 +227,4 @@ const RenderJudge = (props: any) => {
   return <>{formData.map(item => RenderComp(item))}</>;
 };
 
-export default RenderJudge;
+export default connect(({ flow }) => ({ depUserTree: flow.depUserTree }))(RenderJudge);

+ 1 - 3
src/components/Flow/components/judgeModal/index.tsx

@@ -16,6 +16,7 @@ const AddCondition = (props: any) => {
           // item.componentName == 'DepartmentField' ||
           item.componentName == ComponentName.Select ||
           item.componentName == ComponentName.MultiSelect ||
+          item.componentName == ComponentName.Number ||
           item.componentName == ComponentName.Money) &&
         item.props.required
       );
@@ -27,10 +28,7 @@ const AddCondition = (props: any) => {
       };
     });
 
-  console.log(data);
-
   const onChange = (values: []) => {
-    console.log(values);
     setValues(values);
   };
 

+ 33 - 6
src/components/Flow/index.tsx

@@ -1,5 +1,5 @@
-import { IAppLoad } from '@antv/xflow';
-import React, { useRef, useEffect } from 'react';
+import { IAppLoad, NsGraphCmd } from '@antv/xflow';
+import React, { useRef, useEffect, useImperativeHandle } from 'react';
 /** 交互组件 */
 import {
   /** XFlow核心组件 */
@@ -33,7 +33,7 @@ import { useCmdConfig, initGraphCmds } from './config-cmd';
 /** 配置Menu */
 import { useMenuConfig } from './config-menu';
 /** 配置Toolbar */
-import { useToolbarConfig } from './config-toolbar';
+import { TOOLBAR_ITEMS, useToolbarConfig } from './config-toolbar';
 /** 配置快捷键 */
 import { useKeybindingConfig } from './config-keybinding';
 import { registerNode } from './node/registerNode';
@@ -49,10 +49,11 @@ export interface IProps {
   meta: { flowId: string; type: 'edit' };
   flowDetail: any;
   onSelectNode?: Function;
+  parentRef?: any;
 }
 
 export const Demo: React.FC<IProps> = props => {
-  const { meta, flowDetail } = props;
+  const { meta, flowDetail, parentRef } = props;
   const isEdit = meta.type == 'edit';
   const toolbarConfig = useToolbarConfig();
   const menuConfig = useMenuConfig();
@@ -61,6 +62,24 @@ export const Demo: React.FC<IProps> = props => {
   const appRef = useRef<IApplication>();
   const commandConfig: any = useCmdConfig(props);
 
+  // 封装供外部主动调用的接口
+  useImperativeHandle(parentRef, () => ({
+    getGraphData: async cb => {
+      appRef.current.commandService.executeCommand<NsGraphCmd.SaveGraphData.IArgs>(
+        TOOLBAR_ITEMS.SAVE_GRAPH_DATA,
+        {
+          saveGraphDataService: (meta, graphData) => {
+            let data = JSON.parse(JSON.stringify(graphData));
+
+            console.log(data);
+            console.log(JSON.stringify(data));
+            cb?.(JSON.stringify(data));
+            return data;
+          },
+        }
+      );
+    },
+  }));
   /**
    * @param app 当前XFlow工作空间
    * @param extensionRegistry 当前XFlow配置项
@@ -101,7 +120,7 @@ export const Demo: React.FC<IProps> = props => {
         minHeight: 0,
         preserveAspectRatio: false,
       },
-      snapline: false
+      snapline: false,
     };
     return isEdit
       ? defaultOption
@@ -194,4 +213,12 @@ export const Demo: React.FC<IProps> = props => {
   );
 };
 
-export default Demo;
+// 高阶组件
+const DemoHoc = Demo => {
+  const forwardRef = (props, ref) => {
+    return <Demo parentRef={ref} {...props}></Demo>;
+  };
+  return React.forwardRef(forwardRef);
+};
+
+export default DemoHoc(Demo);

+ 59 - 7
src/components/Flow/node/auditNode/index.tsx

@@ -1,14 +1,15 @@
-import React from 'react';
+import React, { useMemo } from 'react';
 AuditServe;
 import AuditServe, { TYPE } from './mapServe';
 // import { Badge } from 'antd';
 import { useXFlowApp, XFlowNodeCommands } from '@antv/xflow';
+import { connect } from 'dva';
 export { AuditServe };
 
-export default function CustomRect(props) {
-  const { size = { width: 130, height: 50 }, data } = props;
+const CustomRect = props => {
+  const { size = { width: 130, height: 50 }, data, depUserTree, roleList } = props;
   const { width, height } = size;
-  const { label, stroke, fill, fontFill, fontSize, type } = data;
+  const { label, stroke, fill, fontFill, fontSize, type = 1, audits, roleID } = data;
   const app = useXFlowApp();
   const handleClick = () => {
     // console.log(data);
@@ -19,10 +20,56 @@ export default function CustomRect(props) {
     // message.success(`${XFlowNodeCommands.SELECT_NODE.label}: 命令执行成功`);
   };
 
+  const contentText = useMemo(() => {
+    let text = '请选择审批人';
+    switch (type) {
+      case TYPE.AUDIT:
+        text = '请选择审批人';
+        break;
+      case TYPE.INITIATOR:
+        text = '所有人';
+        break;
+      case TYPE.COPYMAN:
+        text = '请选择抄送人';
+        break;
+    }
+    const getName = (id, data) => {
+      let name = '';
+      for (let i = 0; i < data.length; i++) {
+        let item = data[i];
+        if (item.ID == id) {
+          return item.title;
+        } else if (item.children?.length > 0) {
+          let title = getName(id, item.children);
+          if (title) return title;
+        }
+      }
+      return name;
+    };
+    if (type != TYPE.AUDIT) {
+      if (audits?.length > 0) {
+        const list = audits
+          .map(item => {
+            return getName(item.value, depUserTree);
+          })
+          .filter(item => item);
+        return list.join(',');
+      } else {
+        return text;
+      }
+    } else {
+      if (roleID) {
+        return roleList.find(item => item.ID == roleID)?.Name;
+      } else {
+        return text;
+      }
+    }
+  }, [audits, type]);
+
   // const type: TYPE = 0;
   const titleDom = () => {
     let color = COLOR.AUDIT;
-    let text = label == '审批节点' ? TITLETEXT.AUDIT : label;
+    let text = label == '动作节点' ? TITLETEXT.AUDIT : label;
     switch (type) {
       case TYPE.AUDIT:
         color = COLOR.AUDIT;
@@ -69,11 +116,16 @@ export default function CustomRect(props) {
           fontSize,
         }}
       >
-        哈哈哈哈哈哈哈哈
+        {contentText}
       </div>
     </div>
   );
-}
+};
+
+export default connect(({ flow }) => ({
+  depUserTree: flow.depUserTree,
+  roleList: flow.roleList,
+}))(CustomRect);
 
 const enum COLOR {
   AUDIT = '#FF943E',

+ 83 - 27
src/components/Flow/node/auditNode/mapServe.tsx

@@ -4,14 +4,22 @@ import { Position, Size, ColorPicker, InputNumberFiled, InputFiled, SelectField
 import { PREFIX } from '../constants';
 import { connect } from 'dva';
 import { UnityAction } from '@/utils/utils';
-import { Button } from 'antd';
+import { Button, Select, TreeSelect } from 'antd';
+
+const { Option } = Select;
 
 export const enum TYPE {
-  AUDIT,
+  AUDIT = 1,
   INITIATOR,
   COPYMAN,
 }
 
+export const typeOption = [
+  { label: '审批人', value: TYPE.AUDIT },
+  { label: '发起人', value: TYPE.INITIATOR },
+  { label: '抄送人', value: TYPE.COPYMAN },
+];
+
 export interface IConfig {
   label?: string;
   x?: number;
@@ -27,23 +35,22 @@ export interface IConfig {
   flow_node_id?: string;
   process_code?: string;
   type: TYPE;
+  roleID: number;
+  audits: { type: string; value: number; origin?: string | number; name?: string }[];
 }
 
 const Component = (props: any) => {
-  const { config, plugin = {}, auditList } = props;
+  const defaultConfig = {
+    type: TYPE.AUDIT,
+  };
+  const { config, plugin = {}, depUserTree, roleList } = props;
   const { updateNode } = plugin;
 
-  const typeOption = [
-    { label: '审批人', value: TYPE.AUDIT },
-    { label: '发起人', value: TYPE.INITIATOR },
-    { label: '抄送人', value: TYPE.COPYMAN },
-  ];
-
   const [nodeConfig, setNodeConfig] = useState<IConfig>({
+    ...defaultConfig,
     ...config,
   });
   const onNodeConfigChange = (key: string, value: number | string | object) => {
-    console.log(key, value);
     if (key) {
       setNodeConfig({
         ...nodeConfig,
@@ -63,11 +70,23 @@ const Component = (props: any) => {
     }
   };
 
+  const handleTreeChange = (values: (string | number)[]) => {
+    const newValues = values.map(cur => {
+      if (typeof cur == 'string' && cur.includes('||')) {
+        return { type: 'user', value: Number(cur.split('||')[0]), origin: cur };
+      } else {
+        return { type: 'dep', value: cur, origin: cur };
+      }
+    });
+    onNodeConfigChange('audits', newValues);
+  };
+
   const onSave = () => {
     UnityAction.emit('NODE_SAVE', nodeConfig);
   };
   useEffect(() => {
     setNodeConfig({
+      ...defaultConfig,
       ...config,
     });
   }, [config]);
@@ -129,24 +148,57 @@ const Component = (props: any) => {
             onNodeConfigChange('count', value);
           }}
         />
+        <div className={`${PREFIX}-node-text-style`}>
+          <InputNumberFiled
+            label="字号"
+            value={nodeConfig.fontSize}
+            width={68}
+            onChange={value => {
+              onNodeConfigChange('fontSize', value);
+            }}
+          />
+          <ColorPicker
+            value={nodeConfig.fontFill}
+            onChange={(value: string) => {
+              onNodeConfigChange('fontFill', value);
+            }}
+          />
+        </div>
+        <div className="group">
+          <label>{typeOption.find(item => item.value == nodeConfig.type)?.label || '审批人'}</label>
+          {nodeConfig.type != TYPE.AUDIT ? (
+            <TreeSelect
+              showSearch
+              multiple
+              allowClear
+              defaultValue={nodeConfig.audits?.map(item => item.origin)}
+              style={{ width: '80%' }}
+              placeholder="请选择"
+              treeData={depUserTree}
+              onChange={values => {
+                handleTreeChange(values);
+              }}
+            />
+          ) : (
+            <Select
+              showSearch
+              style={{ width: '100%' }}
+              filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
+              onChange={value => {
+                onNodeConfigChange('roleID', value);
+              }}
+            >
+              {roleList &&
+                roleList.map(item => (
+                  <Option key={item.ID} value={item.ID + ''}>
+                    {item.Name}
+                  </Option>
+                ))}
+            </Select>
+          )}
+        </div>
       </div>
 
-      <div className={`${PREFIX}-node-text-style`}>
-        <InputNumberFiled
-          label="字号"
-          value={nodeConfig.fontSize}
-          width={68}
-          onChange={value => {
-            onNodeConfigChange('fontSize', value);
-          }}
-        />
-        <ColorPicker
-          value={nodeConfig.fontFill}
-          onChange={(value: string) => {
-            onNodeConfigChange('fontFill', value);
-          }}
-        />
-      </div>
       <Button style={{ marginTop: 20 }} type="primary" onClick={onSave}>
         保存
       </Button>
@@ -162,4 +214,8 @@ function RecthServe(props: any) {
   );
 }
 
-export default connect(({ xflow }) => ({ auditList: xflow.auditList }))(RecthServe);
+export default connect(({ xflow, flow }) => ({
+  auditList: xflow.auditList,
+  depUserTree: flow.depUserTree,
+  roleList: flow.roleList,
+}))(RecthServe);

+ 48 - 49
src/components/Flow/node/judgeNode/index.tsx

@@ -1,57 +1,51 @@
-import React from 'react';
+import React, { useEffect, useMemo } from 'react';
 judgeServe;
-import judgeServe, { TYPE } from './mapServe';
+import judgeServe, { ComponentName, FormItem, TYPE } from './mapServe';
 // import { Badge } from 'antd';
 import { useXFlowApp, XFlowNodeCommands } from '@antv/xflow';
+import { JudgeType } from '../../components/judgeComponent';
+import { connect } from 'dva';
 export { judgeServe };
 
-export default function CustomRect(props) {
-  const { size = { width: 130, height: 50 }, data } = props;
+const JudgeRect = props => {
+  const { size = { width: 130, height: 50 }, data, depUserTree } = props;
   const { width, height } = size;
-  const { label, stroke, fill, fontFill, fontSize, type } = data;
-  const app = useXFlowApp();
-  const handleClick = () => {
-    // console.log(data);
-    app.executeCommand(XFlowNodeCommands.SELECT_NODE.id, {
-      nodeId: data.id,
-    });
-    // console.log('XFlowNodeCommands.SELECT_NODE.id', data);
-    // message.success(`${XFlowNodeCommands.SELECT_NODE.label}: 命令执行成功`);
-  };
+  const { label, stroke, fill, fontFill, fontSize, type, priority, formItems } = data;
 
-  // const type: TYPE = 0;
-  const titleDom = () => {
-    let color = COLOR.AUDIT;
-    let text = label == '审批节点' ? TITLETEXT.AUDIT : label;
-    switch (type) {
-      case TYPE.AUDIT:
-        color = COLOR.AUDIT;
-        text = TITLETEXT.AUDIT;
-        break;
-      case TYPE.INITIATOR:
-        color = COLOR.INITIATOR;
-        text = TITLETEXT.INITIATOR;
-        break;
-      case TYPE.COPYMAN:
-        color = COLOR.COPYMAN;
-        text = TITLETEXT.COPYMAN;
-        break;
+  const contentText = useMemo(() => {
+    const getName = (id, data) => {
+      let name = '';
+      for (let i = 0; i < data.length; i++) {
+        let item = data[i];
+        if (item.ID == id) {
+          return item.title;
+        } else if (item.children?.length > 0) {
+          let title = getName(id, item.children);
+          if (title) return title;
+        }
+      }
+      return name;
+    };
+
+    if (formItems) {
+      let text = 'XXX';
+      let data: FormItem[] = JSON.parse(formItems);
+      data.forEach((item: FormItem) => {
+        let judge: JudgeType = item.judge;
+        switch (judge?.type) {
+          case ComponentName.Inner:
+            const list = judge?.values
+              .map(item => {
+                return getName(item.value, depUserTree);
+              })
+              .filter(item => item);
+            text = '发起人属于:' + list.join('或');
+        }
+      });
+      return text;
     }
-    return (
-      <div
-        style={{
-          width: '100%',
-          height: `${fontSize + 16}px`,
-          paddingLeft: '6px',
-          backgroundColor: color,
-          color: 'white',
-          fontSize,
-        }}
-      >
-        {text}
-      </div>
-    );
-  };
+  }, [formItems]);
+
   return (
     <div
       style={{
@@ -61,7 +55,8 @@ export default function CustomRect(props) {
         boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)',
       }}
     >
-      <span style={{ color: '#15BC83' }}>条件1</span>
+      <span style={{ color: '##7E8185', float: 'right', fontSize: '8px' }}>优先级{priority}</span>
+      <div style={{ color: '#15BC83' }}>{label}</div>
       <div
         style={{
           height: `${height - 32}px`,
@@ -69,11 +64,15 @@ export default function CustomRect(props) {
           textOverflow: 'ellipsis',
         }}
       >
-        哈哈哈哈哈哈哈哈
+        {contentText}
       </div>
     </div>
   );
-}
+};
+
+export default connect(({ flow }) => ({
+  depUserTree: flow.depUserTree,
+}))(JudgeRect);
 
 const enum COLOR {
   AUDIT = '#FF943E',

+ 54 - 53
src/components/Flow/node/judgeNode/mapServe.tsx

@@ -20,6 +20,7 @@ export const enum ComponentName {
   Select = 'DDSelectField',
   Money = 'MoneyField',
   MultiSelect = 'DDMultiSelectField',
+  Number = 'NumberField',
 }
 
 export interface IConfig {
@@ -57,63 +58,62 @@ const Component = (props: any) => {
   const { config, plugin = {}, formItems } = props;
   const { updateNode } = plugin;
 
-  const formData: FormItem[] = [
-    {
-      componentName: 'InnerContactField',
-      props: {
-        label: '申请人',
-        id: 'InnerContactField-JEQRQ5VH',
-        required: true,
-      },
-    },
-    {
-      componentName: 'DepartmentField',
-      props: {
-        label: '选择部门',
-        id: 'DepartmentField_1VALX0GTRNVK0',
-        required: true,
-      },
-    },
-    {
-      componentName: 'DDSelectField',
-      props: {
-        id: 'DDSelectField_LWFCJRK508W0',
-        label: '文件类型',
-        options: [
-          '{"value":"新增|FT008","key":"option_1IXTB1VDV9EO0"}',
-          '{"value":"补充|FT009","key":"option_1DVWNV9BNZNK0"}',
-        ],
-        required: true,
-      },
-    },
-    {
-      componentName: 'DDSelectField',
-      props: {
-        id: 'DDSelectField_21WUQ0OWR7R40',
-        label: '是否外带',
-        options: [
-          '{"value":"是","key":"option_DUSP6XANFKO0"}',
-          '{"value":"否","key":"option_CC5VQ63ZLJK0"}',
-        ],
-        required: true,
-      },
-    },
-    {
-      componentName: 'MoneyField',
-      props: {
-        id: 'MoneyField-JSCUC2GG',
-        label: '文件金额(元)',
-        placeholder: '请输入金额',
-        required: true,
-      },
-    },
-  ];
+  // const formData: FormItem[] = [
+  //   {
+  //     componentName: 'InnerContactField',
+  //     props: {
+  //       label: '申请人',
+  //       id: 'InnerContactField-JEQRQ5VH',
+  //       required: true,
+  //     },
+  //   },
+  //   {
+  //     componentName: 'DepartmentField',
+  //     props: {
+  //       label: '选择部门',
+  //       id: 'DepartmentField_1VALX0GTRNVK0',
+  //       required: true,
+  //     },
+  //   },
+  //   {
+  //     componentName: 'DDSelectField',
+  //     props: {
+  //       id: 'DDSelectField_LWFCJRK508W0',
+  //       label: '文件类型',
+  //       options: [
+  //         '{"value":"新增|FT008","key":"option_1IXTB1VDV9EO0"}',
+  //         '{"value":"补充|FT009","key":"option_1DVWNV9BNZNK0"}',
+  //       ],
+  //       required: true,
+  //     },
+  //   },
+  //   {
+  //     componentName: 'DDSelectField',
+  //     props: {
+  //       id: 'DDSelectField_21WUQ0OWR7R40',
+  //       label: '是否外带',
+  //       options: [
+  //         '{"value":"是","key":"option_DUSP6XANFKO0"}',
+  //         '{"value":"否","key":"option_CC5VQ63ZLJK0"}',
+  //       ],
+  //       required: true,
+  //     },
+  //   },
+  //   {
+  //     componentName: 'MoneyField',
+  //     props: {
+  //       id: 'MoneyField-JSCUC2GG',
+  //       label: '文件金额(元)',
+  //       placeholder: '请输入金额',
+  //       required: true,
+  //     },
+  //   },
+  // ];
 
   const [nodeConfig, setNodeConfig] = useState<IConfig>({
     ...config,
   });
   const onNodeConfigChange = (key: string, value: number | string | object) => {
-    console.log(key, value);
     if (key) {
       setNodeConfig({
         ...nodeConfig,
@@ -132,7 +132,6 @@ const Component = (props: any) => {
       });
     }
   };
-  console.log(nodeConfig);
 
   const onSave = () => {
     UnityAction.emit('NODE_SAVE', nodeConfig);
@@ -221,12 +220,14 @@ const Component = (props: any) => {
           items={formItems}
           formItems={nodeConfig.formItems}
           onOk={(values: FormItem[]) => {
+            console.log('===formItems===', values);
             onNodeConfigChange('formItems', JSON.stringify(values));
           }}
         />
         <RenderJudge
           formItems={nodeConfig.formItems}
           onChange={(values: FormItem[]) => {
+            console.log('===formItems===', values);
             onNodeConfigChange('formItems', JSON.stringify(values));
           }}
         />

+ 4 - 4
src/components/Flow/node/registerNode.tsx

@@ -26,20 +26,20 @@ export const registerNode = [
   },
   {
     component: AuditNode,
-    popover: () => <div>审批节点</div>,
+    popover: () => <div>动作节点</div>,
     name: 'custom-audit',
     width: 130,
     height: 50,
-    label: '审批节点',
+    label: '动作节点',
     service: AuditServe,
   },
   {
     component: judgeNode,
-    popover: () => <div>审批节点</div>,
+    popover: () => <div>条件节点</div>,
     name: 'custom-judge',
     width: 130,
     height: 50,
-    label: '审批节点',
+    label: '条件节点',
     service: judgeServe,
   },
 ];

+ 1 - 0
src/models/xflow.js

@@ -7,6 +7,7 @@ export default {
     OSSData: {},
     flowDetail: { nodes: [], edges: [] },
     auditList: [],
+    formData: [],
   },
 
   effects: {

+ 56 - 27
src/pages/PurchaseAdmin/PurchaseList/Flow/Audit.js

@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+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';
@@ -7,46 +7,75 @@ 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 } = props;
-  const [formData, setFormData] = useState([]);
-  const flowDetail = {
-    nodes: [],
-    edgs: [],
-  };
-  const onChange = valuse => {
+  const { roleList, currentItem, dispatch, formItems, formData, flowDetail } = props;
+  const ref = useRef();
+
+  const curItem = useMemo(() => {
+    return currentItem || localStorage.getItem('currentAudit');
+  }, [currentItem, localStorage.getItem('currentAudit')]);
+
+  useEffect(() => {
+    // dispatch({
+    //   type: 'flow/queryProcessFlows',
+    //   payload: { ids: Number(curItem.id) },
+    // });
+    dispatch({
+      type: 'flow/fetchDepV2',
+    });
+  }, []);
+  const onChange = values => {
     dispatch({
       type: 'xflow/save',
       payload: {
-        formData: valuse,
+        formData: values,
       },
     });
   };
+
+  const handleSaveClick = async () => {
+    const data = await ref.current.getGraphData(data => {
+      let param = {
+        // name: curItem.name,
+        id: Number(curItem.id),
+        form_json: JSON.stringify(formItems),
+        process_json: data,
+      };
+      dispatch({ type: 'flow/saveAuditFlowInfo', payload: param });
+    });
+  };
   return (
-    <Tabs defaultActiveKey="1">
-      <TabPane tab="表单设计" key="1">
-        <AuditForm onChange={values => onChange(values)} />
-      </TabPane>
-      <TabPane tab="流程控制" key="2">
-        <Flow
-          meta={{ type: 'edit', flowId: 2 }}
-          flowDetail={flowDetail}
-          // onUpdate={node => this.onUpdate(node)}
-        />
-      </TabPane>
-    </Tabs>
-    // <div>
-    //
-    //
-    // </div>
+    <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', flowId: curItem.id }} flowDetail={flowDetail} ref={ref} />
+        </TabPane>
+      </Tabs>
+      <Button
+        type="primary"
+        onClick={handleSaveClick}
+        style={{ position: 'absolute', right: 0, top: 0 }}
+      >
+        保存
+      </Button>
+    </div>
   );
 }
-export default connect(({ flow, loading }) => ({
+export default connect(({ flow, loading, xflow }) => ({
   roleList: flow.roleList,
   currentItem: flow.current,
   loading: loading.models.purchaseList2,
+  formItems: xflow.formData,
+  flowDetail: flow.flowDetail,
+  formData: flow.formData,
 }))(Audit);

+ 8 - 11
src/pages/PurchaseAdmin/PurchaseList/Flow/AuditList.js

@@ -18,7 +18,7 @@ function Audit(props) {
   const columns = [
     {
       title: '审批流名称',
-      dataIndex: ['list','name'],
+      dataIndex: ['list', 'name'],
     },
     {
       title: '操作',
@@ -51,15 +51,16 @@ function Audit(props) {
       [type]: visible,
     });
   };
-  const setCurrentNode = (item) => {
+  const setCurrentNode = item => {
+    localStorage.setItem('currentAuditId', item.list);
     dispatch({
       type: 'flow/save',
       payload: {
         current: item.list,
-      }
-    })
-    router.push("/home/audit")
-  }
+      },
+    });
+    router.push('/home/audit');
+  };
 
   useEffect(() => {
     dispatch({
@@ -80,11 +81,7 @@ function Audit(props) {
         </Form>
       </div>
 
-      <Table
-        rowKey="id"
-        dataSource={list}
-        columns={columns}
-      />
+      <Table rowKey="id" dataSource={list} columns={columns} />
       <AuditModal
         visible={visible.audit}
         onOk={handleAuditOk}

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

@@ -49,6 +49,9 @@ class FlowPage extends React.PureComponent {
     dispatch({
       type: 'xflow/queryAuditList',
     });
+    dispatch({
+      type: 'xflow/fetchDepV2',
+    });
 
     UnityAction.on('NODE_SAVE', nodeConfig => {
       this.onUpdate(nodeConfig);

+ 66 - 1
src/pages/PurchaseAdmin/PurchaseList/Flow/models/flow.js

@@ -7,21 +7,52 @@ import {
   updateNode,
   queryFlowList,
   queryDingTemplateList,
+  saveAuditFlowInfo,
+  queryDepV2,
+  queryProcessFlows,
 } from '@/services/boom';
 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;
+}
+
 export default {
   namespace: 'flow',
   state: {
     flowDetail: { nodes: [], edges: [] },
+    formData: {},
     auditList: [],
     flowList: [],
     projectList: [],
     current: {},
     roleList: [],
     templateList: [],
+    depUserTree: [],
   },
 
   effects: {
@@ -105,13 +136,47 @@ export default {
     *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 },
         });
       }
     },
+    *saveAuditFlowInfo({ payload, callback }, { call, put }) {
+      const response = yield call(saveAuditFlowInfo, payload);
+      if (response) {
+        message.success('保存成功');
+        callback && callback();
+      }
+    },
+    *fetchDepV2({ payload, callback }, { call, put }) {
+      const response = yield call(queryDepV2, { pageSize: 999999 });
+
+      console.log('=======fetchDepV2===========', response);
+      if (response) {
+        // const depUserTree = response.data?.list;
+        const depUserTree = response.data.list.map(item => {
+          return getDepUserTree(item);
+        });
+        console.log('=======fetchDepV2===========', depUserTree);
+        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: JSON.parse(data[0].process_json),
+            formData: JSON.parse(data[0].form_json),
+          },
+        });
+      }
+    },
   },
 
   reducers: {

+ 22 - 2
src/services/boom.js

@@ -125,7 +125,7 @@ export async function queryDingInstanceExecute(params) {
     body: params,
   });
   if (res.data.errcode != 0) {
-    message.error("审批失败,请联系管理员。");
+    message.error('审批失败,请联系管理员。');
     throw new Error(res.data.errmsg);
   }
   return res;
@@ -360,6 +360,26 @@ export async function bindDDCode(userId, code) {
   let res = await request(`/api/v1/purchase/bom/ding/set-ding-user-code?ucode=${userId}:${code}`, {
     method: 'GET',
   });
- 
+
+  return res.data;
+}
+
+export async function saveAuditFlowInfo(data) {
+  return request(`/purchase/flow/info`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
+//获取部门结构
+export async function queryDepV2(params) {
+  return request(`/api/v2/dep?${stringify(params)}`);
+}
+
+export async function queryProcessFlows(params) {
+  let res = await request(`/purchase/process/get-flows?${stringify(params)}`, {
+    method: 'GET',
+  });
+
   return res.data;
 }