|
@@ -1,226 +0,0 @@
|
|
|
-// 根据传入的elements、node节点、edge节点对elements元素进行再计算
|
|
|
-
|
|
|
-import { ArrowHeadType, isEdge, isNode, Position } from 'react-flow-renderer'
|
|
|
-import { buildUUID } from '@/utils/uuid'
|
|
|
-
|
|
|
-import type { Edge, Elements, Node, XYPosition } from 'react-flow-renderer'
|
|
|
-import { ParticipantMode } from './enum'
|
|
|
-
|
|
|
-export enum genreateElementEnum {
|
|
|
- ADD = 'add',
|
|
|
- DEL = 'del'
|
|
|
-}
|
|
|
-
|
|
|
-/** 通过传入的新的node节点以及当前操作的edge构建新的elements */
|
|
|
-function buildWithNewNode(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: 500, y: sort * 200 },
|
|
|
- type: 'common',
|
|
|
- data: { sort }
|
|
|
- })
|
|
|
-
|
|
|
- newElements.push({
|
|
|
- id: buildUUID(),
|
|
|
- source: edgeSid,
|
|
|
- target: newNode.id,
|
|
|
- type: 'common',
|
|
|
- arrowHeadType: ArrowHeadType.Arrow
|
|
|
- })
|
|
|
- return newElements.map(item => {
|
|
|
- if (isNode(item)) {
|
|
|
- return { ...item, position: { ...item.position, y: item.data?.sort * 200 } }
|
|
|
- }
|
|
|
- return item
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-/** 传入需要删除的node构建新的elements */
|
|
|
-function buildWithDeletedNode(elements: Elements, deletedNode?: Node | null) {
|
|
|
- if (!deletedNode) return elements
|
|
|
- const {
|
|
|
- id,
|
|
|
- data: { sort }
|
|
|
- } = deletedNode
|
|
|
- // 1.先找到node关联的的那两条线
|
|
|
- const upEdge: Edge = elements.find(item => isEdge(item) && item.target === id)
|
|
|
- const downEdge: Edge = elements.find(item => isEdge(item) && item.source === id)
|
|
|
- // 2. 删除对应的edge以及node以及重写sort
|
|
|
- return elements
|
|
|
- .filter(item => item.id !== id && item.id !== downEdge.id)
|
|
|
- .map(item => {
|
|
|
- if (isNode(item) && item.data?.sort > sort)
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- data: { sort: item.data?.sort - 1 },
|
|
|
- position: { ...item.position, y: (item.data?.sort - 1) * 200 }
|
|
|
- }
|
|
|
- if (isEdge(item) && item.id === upEdge.id) {
|
|
|
- return { ...item, target: downEdge.target }
|
|
|
- }
|
|
|
- return item
|
|
|
- })
|
|
|
-}
|
|
|
-export const generateElements = (opreate: genreateElementEnum, elements: Elements) =>
|
|
|
- opreate === genreateElementEnum.ADD
|
|
|
- ? (newNode?: Node | null, oldEdge?: Edge | null) => buildWithNewNode(elements, newNode, oldEdge)
|
|
|
- : (deletedNode?: Node | null) => buildWithDeletedNode(elements, deletedNode)
|
|
|
-
|
|
|
-// export function generateElements(elements: Elements, newNode?: Node | null, oldEdge?: Edge | null) {
|
|
|
-
|
|
|
-// }
|
|
|
-
|
|
|
-// this helper function returns the intersection point
|
|
|
-// of the line between the center of the intersectionNode and the target node
|
|
|
-function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition {
|
|
|
- // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
|
|
|
- const {
|
|
|
- width: intersectionNodeWidth,
|
|
|
- height: intersectionNodeHeight,
|
|
|
- position: intersectionNodePosition
|
|
|
- } = intersectionNode.__rf
|
|
|
- const targetPosition = targetNode.__rf.position
|
|
|
-
|
|
|
- const w = intersectionNodeWidth / 2
|
|
|
- const h = intersectionNodeHeight / 2
|
|
|
-
|
|
|
- const x2 = intersectionNodePosition.x + w
|
|
|
- const y2 = intersectionNodePosition.y + h
|
|
|
- const x1 = targetPosition.x + w
|
|
|
- const y1 = targetPosition.y + h
|
|
|
-
|
|
|
- const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h)
|
|
|
- const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h)
|
|
|
- const a = 1 / (Math.abs(xx1) + Math.abs(yy1))
|
|
|
- const xx3 = a * xx1
|
|
|
- const yy3 = a * yy1
|
|
|
- const x = w * (xx3 + yy3) + x2
|
|
|
- const y = h * (-xx3 + yy3) + y2
|
|
|
-
|
|
|
- return { x, y }
|
|
|
-}
|
|
|
-
|
|
|
-// returns the position (top,right,bottom or right) passed node compared to the intersection point
|
|
|
-function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
|
|
|
- const n = { ...node.__rf.position, ...node.__rf }
|
|
|
- const nx = Math.round(n.x)
|
|
|
- const ny = Math.round(n.y)
|
|
|
- const px = Math.round(intersectionPoint.x)
|
|
|
- const py = Math.round(intersectionPoint.y)
|
|
|
-
|
|
|
- if (px <= nx + 1) {
|
|
|
- return Position.Left
|
|
|
- }
|
|
|
- if (px >= nx + n.width - 1) {
|
|
|
- return Position.Right
|
|
|
- }
|
|
|
- if (py <= ny + 1) {
|
|
|
- return Position.Top
|
|
|
- }
|
|
|
- if (py >= n.y + n.height - 1) {
|
|
|
- return Position.Bottom
|
|
|
- }
|
|
|
-
|
|
|
- return Position.Top
|
|
|
-}
|
|
|
-
|
|
|
-// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
|
|
|
-export function getEdgeParams(source: Node, target: Node) {
|
|
|
- const sourceIntersectionPoint = getNodeIntersection(source, target)
|
|
|
- const targetIntersectionPoint = getNodeIntersection(target, source)
|
|
|
-
|
|
|
- const sourcePos = getEdgePosition(source, sourceIntersectionPoint)
|
|
|
- const targetPos = getEdgePosition(target, targetIntersectionPoint)
|
|
|
-
|
|
|
- return {
|
|
|
- sx: sourceIntersectionPoint.x,
|
|
|
- sy: sourceIntersectionPoint.y,
|
|
|
- tx: targetIntersectionPoint.x,
|
|
|
- ty: targetIntersectionPoint.y,
|
|
|
- sourcePos,
|
|
|
- targetPos
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-export const participantSchema = {
|
|
|
- type: 'object',
|
|
|
- properties: {
|
|
|
- participantMode: {
|
|
|
- type: 'string',
|
|
|
- title: '',
|
|
|
- required: true,
|
|
|
- 'x-decorator': 'FormItem',
|
|
|
- 'x-component': 'Select',
|
|
|
- default: ParticipantMode.ACCOUNT,
|
|
|
- enum: [
|
|
|
- { label: '仅用户模式', value: ParticipantMode.ACCOUNT }
|
|
|
- // { label: '角色模式', value: ParticipantMode.ROLE }
|
|
|
- ],
|
|
|
- 'x-index': 1
|
|
|
- },
|
|
|
- name: {
|
|
|
- type: 'string',
|
|
|
- title: '',
|
|
|
- required: true,
|
|
|
- 'x-decorator': 'FormItem',
|
|
|
- 'x-component': 'Input',
|
|
|
- 'x-display': 'none',
|
|
|
- 'x-index': 4
|
|
|
- },
|
|
|
- institutionID: {
|
|
|
- type: 'string',
|
|
|
- title: '',
|
|
|
- required: true,
|
|
|
- 'x-decorator': 'FormItem',
|
|
|
- 'x-component': 'Select',
|
|
|
- 'x-component-props': {
|
|
|
- placeholder: '请选择单位',
|
|
|
- showSearch: true,
|
|
|
- virtual: true,
|
|
|
- optionFilterProp: 'label'
|
|
|
- },
|
|
|
- 'x-reactions': ['{{useAsyncDataSource(loadInstitutionList)}}'],
|
|
|
- 'x-index': 3
|
|
|
- },
|
|
|
- ID: {
|
|
|
- type: 'string',
|
|
|
- title: '',
|
|
|
- required: true,
|
|
|
- 'x-decorator': 'FormItem',
|
|
|
- 'x-component': 'Select',
|
|
|
- 'x-component-props': {
|
|
|
- placeholder: '请选择用户',
|
|
|
- showSearch: true,
|
|
|
- optionFilterProp: 'label'
|
|
|
- },
|
|
|
- 'x-index': 4
|
|
|
- }
|
|
|
- }
|
|
|
-}
|