lanjianrong 3 anni fa
parent
commit
f315bee0ae

+ 0 - 0
src/components/Flow/index.d.ts


+ 26 - 20
src/components/Flow/src/components/Edge/Edge.tsx

@@ -4,11 +4,12 @@ import { Button, Dropdown, Menu, Popover } from 'antd'
 import React, { useState, useContext } from 'react'
 import { getBezierPath, getEdgeCenter, getMarkerEnd } from 'react-flow-renderer'
 import { Actions, FlowContext } from '../../context'
+import { generateElements } from '../../util'
 import styles from './index.less'
 
 const foreignObjectSize = 40
 
-const renderMenu = ({ dispatch, elements, togglePopver, ...node }) => {
+const renderMenu = ({ dispatch, elements, togglePopver, id }) => {
   const setElements = els => {
     dispatch({
       type: Actions.SET_ELEMENTS,
@@ -33,13 +34,17 @@ const renderMenu = ({ dispatch, elements, togglePopver, ...node }) => {
   }
 
   const addAuditor = () => {
+    // console.log(buildUUID())
+
     const newNode = {
       id: buildUUID(),
       tpye: 'input',
-      position: { x: 400, y: 0 },
+      // position: { x: 400, y: 0 },
       data: {}
     }
-    setElements(elements.concat(newNode))
+    const currentEdge = elements.find(item => item.id === id)
+    setElements(generateElements(elements, newNode, currentEdge))
+    togglePopver(false)
   }
 
   return (
@@ -56,18 +61,21 @@ const renderMenu = ({ dispatch, elements, togglePopver, ...node }) => {
   )
 }
 
-export function ButtonEdge({
-  id,
-  sourceX,
-  sourceY,
-  targetX,
-  targetY,
-  sourcePosition,
-  targetPosition,
-  style = {},
-  arrowHeadType,
-  markerEndId
-}) {
+export function CommonEdge(props) {
+  const {
+    id,
+    sourceX,
+    sourceY,
+    targetX,
+    targetY,
+    sourcePosition,
+    targetPosition,
+    style = {},
+    arrowHeadType,
+    markerEndId
+  } = props
+  // console.log('props', props)
+
   const [visible, setVisible] = useState(false)
   const { state, dispatch } = useContext(FlowContext)
   const { elements } = state
@@ -88,8 +96,6 @@ export function ButtonEdge({
   })
 
   const togglePopver = (isShow: boolean) => {
-    console.log(isShow)
-
     setVisible(isShow)
   }
 
@@ -109,11 +115,11 @@ export function ButtonEdge({
         y={edgeCenterY - foreignObjectSize / 2}>
         <div className={styles.addIcon}>
           <Popover
-            content={renderMenu({ elements, dispatch, togglePopver })}
+            content={renderMenu({ elements, dispatch, togglePopver, id })}
             trigger="click"
             placement="right"
-            // visible={visible}
-            // destroyTooltipOnHide
+            visible={visible}
+            destroyTooltipOnHide
             // onVisibleChange={togglePopver}
             overlayClassName="flow-popover">
             <Button

+ 8 - 6
src/components/Flow/src/components/Graph/index.tsx

@@ -1,18 +1,19 @@
 import { useContext } from 'react'
-import ReactFlow, { Background, Controls, MiniMap } from 'react-flow-renderer'
+import ReactFlow, { Background, MiniMap, Controls } from 'react-flow-renderer'
 import { FlowContext } from '../../context'
 
 import type { NodeTypesType, EdgeTypesType } from 'react-flow-renderer'
-import { InputNode, OutputNode } from '../Node'
-import { ButtonEdge } from '../Edge/Edge'
+import { CommonNode, InputNode, OutputNode } from '../Node'
+import { CommonEdge } from '../Edge'
 
 const nodeTypes: NodeTypesType = {
   start: InputNode,
-  end: OutputNode
+  end: OutputNode,
+  common: CommonNode
 }
 
 const edgeTypes: EdgeTypesType = {
-  add: ButtonEdge
+  common: CommonEdge
 }
 
 export default function FlowGroph() {
@@ -20,7 +21,7 @@ export default function FlowGroph() {
   const { elements } = state
 
   const defaultOptions = {
-    nodesDraggable: false, // 不可拖拽
+    // nodesDraggable: false, // 不可拖拽
     zoomOnScroll: false, // 使用鼠标滚轮或触控板放大和缩小图形
     zoomOnPinch: false // 使用捏合放大和缩小图形
   }
@@ -28,6 +29,7 @@ export default function FlowGroph() {
     <ReactFlow {...defaultOptions} elements={elements} nodeTypes={nodeTypes} edgeTypes={edgeTypes}>
       <MiniMap />
       <Background />
+      <Controls showZoom={true} showFitView={false} showInteractive={false} />
     </ReactFlow>
   )
 }

+ 28 - 3
src/components/Flow/src/components/Node/index.tsx

@@ -1,5 +1,7 @@
 import { Handle } from 'react-flow-renderer'
-
+import { FlowContext } from '../../context'
+import { useContext } from 'react'
+import { RightOutlined } from '@ant-design/icons'
 export const InputNode = () => {
   return (
     <>
@@ -9,7 +11,7 @@ export const InputNode = () => {
         </div>
         <div className="text-14px p-4 bg-white rounded-b-sm">具有新建权限的员工</div>
       </div>
-      <Handle type="source" id="e-1" position="bottom" />
+      <Handle type="source" position="bottom" />
     </>
   )
 }
@@ -17,8 +19,31 @@ export const InputNode = () => {
 export const OutputNode = () => {
   return (
     <>
-      <Handle type="target" id="e-1" position="top" />
+      <Handle type="target" position="top" />
       <div className="px-4 pt-2 pb-4 w-52 text-center">流程结束</div>
     </>
   )
 }
+
+export const CommonNode = props => {
+  // console.log(props)
+
+  const { state } = useContext(FlowContext)
+  return (
+    <>
+      <Handle type="target" position="top" />
+      <div className="shadow-card min-h-18 w-52 cursor-default">
+        <div className="bg-hex-f78b22 text-light-500 leading-6 h-6 px-4 text-12px rounded-t-sm">
+          发起人
+        </div>
+        <div className="text-14px p-4 bg-white rounded-b-sm flex justify-between">
+          <span>请选择选批人</span>
+          <span>
+            <RightOutlined />
+          </span>
+        </div>
+      </div>
+      <Handle type="source" position="bottom" />
+    </>
+  )
+}

+ 14 - 7
src/components/Flow/src/context/index.tsx

@@ -19,17 +19,24 @@ const initialState: InitialState = {
   // node节点或者是edge
   elements: [
     {
-      id: 'ewb-1',
+      id: '89e43a46-88da-4243-ad0b-3c701819ff63',
       type: 'start',
-      position: { x: 250, y: 0 }
+      position: { x: 250, y: 0 },
+      data: { sort: 0 }
     },
-    { id: 'ewb-2', type: 'end', position: { x: 250, y: 300 } },
 
     {
-      id: 'edge-1-2',
-      source: 'ewb-1',
-      target: 'ewb-2',
-      type: 'add'
+      id: '83282d24-22d9-4bd8-a6bf-71d6df94f29e',
+      type: 'end',
+      position: { x: 250, y: 200 },
+      data: { sort: 1 }
+    },
+
+    {
+      id: '29b4469f-9522-4688-8a35-a57ca4875a7a',
+      source: '89e43a46-88da-4243-ad0b-3c701819ff63',
+      target: '83282d24-22d9-4bd8-a6bf-71d6df94f29e',
+      type: 'common'
     }
   ],
   flowData: new Map(),

+ 52 - 2
src/components/Flow/src/util.ts

@@ -1,3 +1,53 @@
-// 根据传入的elements 以及新的node节点对elements元素进行再计算
+// 根据传入的elements、node节点、edge节点对elements元素进行再计算
 
-export function generateElements(elements, node) {}
+import { isEdge, isNode } from 'react-flow-renderer'
+import type { Edge, Elements, Node } from 'react-flow-renderer'
+import { buildUUID } from '@/utils/uuid'
+
+export function generateElements(elements: Elements, newNode?: Node | null, oldEdge?: Edge | null) {
+  if (!newNode || !oldEdge) return elements
+  // 取出当前操作edge的数据
+  const { id: edgeId, source: edgeSid, target: edgeTid } = oldEdge
+  // 原来node节点中的sort
+  const sort = elements.find(item => item.id === edgeTid)?.data?.sort
+  // console.log(sort)
+
+  let oldIdx
+  const newElements: Elements = [...elements].map((item, idx) => {
+    if (isNode(item)) {
+      if (item.data?.sort >= sort) {
+        return { ...item, data: { ...item.data, sort: item.data.sort + 1 } }
+      }
+      if (item.id === edgeTid) {
+        oldIdx = idx
+      }
+      return item
+    } else if (isEdge(item) && item.id === edgeId) {
+      // 修改原来edge的source
+      const edge = { ...item, source: newNode.id }
+      return edge
+    }
+
+    return item
+  })
+  // 添加新的node和edge
+  // TODO: 在当前oldEdge target指向的节点前插入node
+  newElements.splice(oldIdx + 1, 0, {
+    ...newNode,
+    position: { x: 250, y: sort * 200 },
+    type: 'common',
+    data: { sort }
+  })
+  console.log(newElements)
+
+  newElements.push({ id: buildUUID(), source: edgeSid, target: newNode.id, type: 'common' })
+  return newElements.map(item => {
+    if (isNode(item)) {
+      if (item.id === '83282d24-22d9-4bd8-a6bf-71d6df94f29e') {
+        console.log(item.data?.sort * 200)
+      }
+      return { ...item, position: { ...item.position, y: item.data?.sort * 200 } }
+    }
+    return item
+  })
+}

+ 2 - 1
src/utils/uuid.ts

@@ -16,7 +16,8 @@ export function buildUUID(): string {
       uuid += hexList[(Math.random() * 16) | 0]
     }
   }
-  return uuid.replace(/-/g, '')
+  // return uuid.replace(/-/g, '')
+  return uuid
 }
 
 let unique = 0