diff --git a/src/BloodNode/index.tsx b/src/BloodNode/index.tsx index 4973216..146a2df 100644 --- a/src/BloodNode/index.tsx +++ b/src/BloodNode/index.tsx @@ -1,76 +1,7 @@ +import { NODE_DANGER, NODE_SELECT, NODE_WARNING, NodeSelect } from '@/ProFlow/constants'; import { ConfigProvider } from 'antd'; -import { createStyles } from 'antd-style'; import { CSSProperties, ReactNode, memo, useRef } from 'react'; - -const useStyles = createStyles(({ css }) => ({ - nodeWrap: css` - width: 320px; - height: 85px; - display: flex; - z-index: 10 !important; - position: absolute; - border-radius: 12px; - padding: 16px 12px; - box-sizing: border-box; - border: 3px solid white; - flex: 1; - background-color: white; - - .img { - width: 48px; - height: 48px; - } - - .content { - width: 230px; - margin-left: 13px; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: flex-start; - - .title { - width: 100%; - display: flex; - flex: 1; - - span { - font-size: 16px; - color: rgba(0, 0, 0, 85%); - line-height: 22px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-align: left; - } - - .dangerLogo { - width: 28px; - height: 16px; - background: #ffeef1; - border-radius: 7px; - margin-left: 8px; - margin-top: 3px; - img { - width: 8px; - height: 9px; - } - } - } - - .des { - font-size: 14px; - color: rgba(0, 0, 0, 45%); - line-height: 20px; - white-space: nowrap; - width: 100%; - overflow: hidden; - text-overflow: ellipsis; - text-align: left; - } - } - `, -})); +import { useStyles } from './styles'; interface BloodNodeProps { logo: string; @@ -80,6 +11,20 @@ interface BloodNodeProps { showIcon?: boolean; icon?: string; className?: string; + selectType?: NodeSelect; +} + +function getClsFromSelectType(select: NodeSelect) { + switch (select) { + case NodeSelect.SELECT: + return NODE_SELECT; + case NodeSelect.DANGER: + return NODE_DANGER; + case NodeSelect.WARNING: + return NODE_WARNING; + default: + return 'nodeDefault'; + } } export interface BloodNodePreviewProps extends BloodNodeProps { @@ -97,34 +42,36 @@ export interface BloodNodePreviewProps extends BloodNodeProps { onClick?: () => void; } -const Preview = memo>(({ title, logo, description, className }) => { - const { styles, cx } = useStyles(); - const cardRef = useRef(null); - - return ( - { - return cardRef.current || document.body; - }} - > - {/* +const Preview = memo>( + ({ title, logo, description, className, selectType = NodeSelect.SELECT }) => { + const { styles, cx } = useStyles(); + const cardRef = useRef(null); + + return ( + { + return cardRef.current || document.body; + }} + > + {/* {children} */} -
- -
-
- {title} - {/* {mainDanger && } +
+ +
+
+ {title} + {/* {mainDanger && } {qualityScore && } */} +
+
{description}
-
{description}
-
- - ); -}); + + ); + }, +); const Default = memo(({ ...props }) => { return ; diff --git a/src/BloodNode/styles.ts b/src/BloodNode/styles.ts new file mode 100644 index 0000000..23a1e59 --- /dev/null +++ b/src/BloodNode/styles.ts @@ -0,0 +1,84 @@ +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, cx, prefixCls }) => ({ + nodeWrap: cx( + `${prefixCls}-xx`, + css` + width: 320px; + height: 85px; + display: flex; + z-index: 10 !important; + position: absolute; + border-radius: 12px; + padding: 16px 12px; + box-sizing: border-box; + border: 3px solid white; + flex: 1; + background-color: white; + + .img { + width: 48px; + height: 48px; + } + + .content { + width: 230px; + margin-left: 13px; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + + .title { + width: 100%; + display: flex; + flex: 1; + + span { + font-size: 16px; + color: rgba(0, 0, 0, 85%); + line-height: 22px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + } + + .dangerLogo { + width: 28px; + height: 16px; + background: #ffeef1; + border-radius: 7px; + margin-left: 8px; + margin-top: 3px; + img { + width: 8px; + height: 9px; + } + } + } + + .des { + font-size: 14px; + color: rgba(0, 0, 0, 45%); + line-height: 20px; + white-space: nowrap; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + } + } + `, + ), + nodeSelected: css` + box-shadow: 0 0 0 3px #1677ff, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, + nodeDanger: css` + box-shadow: 0 0 0 3px #f7636e, 0 1px 4px 1px rgba(0, 0, 0, 8%); + `, + nodeWarning: css` + box-shadow: 0 0 0 3px #ef9d3b, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, + nodeDefault: css``, +})); diff --git a/src/ProFlow/constants.tsx b/src/ProFlow/constants.tsx index 4e1b4da..6bab6c1 100644 --- a/src/ProFlow/constants.tsx +++ b/src/ProFlow/constants.tsx @@ -1,8 +1,15 @@ import { Node } from 'reactflow'; +export enum NodeSelect { + SELECT = 'SELECT', + DANGER = 'DANGER', + WARNING = 'WARNING', + DEFAULT = 'DEFAULT', +} export interface ProFlowNode { id: string; type: string; + select?: NodeSelect; data: ProFlowNodeData; } @@ -35,7 +42,7 @@ export interface NodeMapItem { dangerCount?: number; type?: 'input' | 'output' | 'default'; className?: string; - selected?: boolean; + select?: NodeSelect; isGroup?: boolean; childrenNeedFold?: boolean; haveAlert?: boolean; @@ -51,3 +58,12 @@ export interface NodeMapItem { } export type NodeMapping = Record; + +export const NODE_SELECT = 'nodeSelected'; +export const NODE_DANGER = 'nodeDanger'; +export const NODE_WARNING = 'nodeWarning'; +export const INIT_NODE = 'initialNode'; +export const NODE_WRAP = 'nodeWrap'; +export const EDGE_SELECT = 'edgeSelected'; +export const EDGE_DANGER = 'edgeDanger'; +export const EDGE_WARNING = 'edgeWarning'; diff --git a/src/ProFlow/demos/ProFlowDemo.tsx b/src/ProFlow/demos/ProFlowDemo.tsx index 31218f8..be8988c 100644 --- a/src/ProFlow/demos/ProFlowDemo.tsx +++ b/src/ProFlow/demos/ProFlowDemo.tsx @@ -1,7 +1,7 @@ import { createStyles } from 'antd-style'; import { memo } from 'react'; import ProFlow from '..'; -import { ProFlowNode } from '../constants'; +import { NodeSelect, ProFlowNode } from '../constants'; const useStyles = createStyles(({ css }) => ({ container: css` @@ -14,6 +14,7 @@ const nodes: ProFlowNode[] = [ { id: 'a1', type: 'BloodNode', + select: NodeSelect.SELECT, data: { title: 'XXX数据源', describe: 'cksadjfnf', @@ -23,6 +24,7 @@ const nodes: ProFlowNode[] = [ { id: 'a2', type: 'BloodNode', + select: NodeSelect.DANGER, data: { title: 'XXX_API', logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', @@ -32,6 +34,7 @@ const nodes: ProFlowNode[] = [ { id: 'a3', type: 'BloodNode', + select: NodeSelect.WARNING, data: { title: 'XXXX产品', logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*ezaYT4wYRBwAAAAAAAAAAAAADvuvAQ/original', diff --git a/src/ProFlow/helper.tsx b/src/ProFlow/helper.tsx index 537d8f5..4eb8999 100644 --- a/src/ProFlow/helper.tsx +++ b/src/ProFlow/helper.tsx @@ -1,7 +1,19 @@ import BloodNode from '@/BloodNode'; import Dagre from '@dagrejs/dagre'; +import { cx } from 'antd-style'; import { Edge, Node, Position } from 'reactflow'; -import { InitialNode, NodeMapItem, NodeMapping, ProFLowEdge, ProFlowNode } from './constants'; +import { + EDGE_DANGER, + EDGE_SELECT, + EDGE_WARNING, + INIT_NODE, + InitialNode, + NodeMapItem, + NodeMapping, + NodeSelect, + ProFLowEdge, + ProFlowNode, +} from './constants'; function getTypeFromEdge(node: NodeMapItem) { if (node.left?.length && node.right?.length) { @@ -23,6 +35,7 @@ export function convertMappingFrom(nodes: ProFlowNode[], edges: ProFLowEdge[]) { id: node.id, nodeType: node.type, // BloodNode | BloodGroup data: node.data, + select: node.select, right: [], left: [], }; @@ -78,6 +91,31 @@ function sortEdges(edges: Edge[]) { return [...lowEdges, ...midEdges, ...highEdges]; } +function getEdgeClsFromNodeSelect(select: NodeSelect) { + switch (select) { + case NodeSelect.SELECT: + return EDGE_SELECT; + case NodeSelect.DANGER: + return EDGE_DANGER; + case NodeSelect.WARNING: + return EDGE_WARNING; + default: + return 'edgeDefault'; + } +} + +function getRenderEdge(node: NodeMapItem, targetNode: NodeMapItem): Edge { + const { id } = node; + const { id: targetId, select = NodeSelect.DEFAULT } = targetNode; + return { + id: `${id}-${targetId}`, + source: id!, + target: targetId!, + type: 'smoothstep', + className: getEdgeClsFromNodeSelect(select), + }; +} + export const getRenderData = ( mapping: NodeMapping, ): { @@ -86,10 +124,12 @@ export const getRenderData = ( } => { const renderNodes: Node[] = []; const renderEdges: Edge[] = []; + // const { styles, cx } = useStyles(); Object.keys(mapping).forEach((id) => { const node = mapping[id]; - + const { select = NodeSelect.DEFAULT } = node; + console.log(select); renderNodes.push({ sourcePosition: Position.Right, targetPosition: Position.Left, @@ -98,29 +138,22 @@ export const getRenderData = ( type: getTypeFromEdge(node), width: 320, height: 83, - className: `initialNode`, + className: cx(INIT_NODE), data: { label: ( ), }, }); if (node.right!.length) { - node.right!.forEach((id: string) => { - renderEdges.push({ - id: `${node.id}-${id}`, - source: node.id!, - target: id, - type: 'smoothstep', - className: `${node.selected && mapping[id].selected ? 'initialNode-selected' : ''} ${ - node.mainDanger || node.subDanger ? 'edgeDanger' : '' - }`, - }); + node.right!.forEach((targetId: string) => { + renderEdges.push(getRenderEdge(node, mapping[targetId])); }); } }); diff --git a/src/ProFlow/index.tsx b/src/ProFlow/index.tsx index d95b76c..3eaaf9d 100644 --- a/src/ProFlow/index.tsx +++ b/src/ProFlow/index.tsx @@ -1,53 +1,25 @@ import ProFlowController from '@/ProFlowController'; -import { createStyles } from 'antd-style'; import { useMemo, type CSSProperties, type MouseEvent as ReactMouseEvent } from 'react'; import ReactFlow, { Background, BackgroundVariant, Edge, Node } from 'reactflow'; import { ProFLowEdge, ProFlowNode } from './constants'; import { convertMappingFrom, getRenderData } from './helper'; +import { useStyles } from './styles'; const MIN_ZOOM = 0.1; -const useStyles = createStyles(({ css }) => ({ - container: css` - width: 100%; - height: 100%; - - .initialNode { - padding: 0; - box-sizing: border-box; - width: 320px; - height: 83px; - border: none; - box-shadow: 0 1px 4px 1px rgba(0, 0, 0, 8%); - border-radius: 8px; - cursor: pointer; - z-index: 1; - } - - .selectable:focus { - box-shadow: none !important; - } - - .selected { - box-shadow: none !important; - } - `, -})); - interface ProFlowProps { onNodeDragStart: (event: ReactMouseEvent, node: Node, nodes: Node[]) => void; onPaneClick: (event: ReactMouseEvent) => void; onNodeClick: (event: ReactMouseEvent, node: Node) => void; nodes: ProFlowNode[]; edges: ProFLowEdge[]; - minZoom?: number; className?: string; style?: CSSProperties; - children?: React.ReactNode; + miniMap?: boolean; } const ProFlow: React.FC> = (props) => { - const { onNodeDragStart, onPaneClick, onNodeClick, nodes, edges } = props; + const { onNodeDragStart, onPaneClick, onNodeClick, nodes, edges, miniMap = true } = props; const { styles, cx } = useStyles(); const mapping = convertMappingFrom(nodes!, edges!); const renderData = useMemo((): { @@ -81,7 +53,7 @@ const ProFlow: React.FC> = (props) => { fitView minZoom={MIN_ZOOM} > - + {miniMap && } ); diff --git a/src/ProFlow/styles.tsx b/src/ProFlow/styles.tsx new file mode 100644 index 0000000..3179466 --- /dev/null +++ b/src/ProFlow/styles.tsx @@ -0,0 +1,47 @@ +import { createStyles } from 'antd-style'; +import { EDGE_DANGER, EDGE_SELECT, EDGE_WARNING, INIT_NODE } from './constants'; + +export const useStyles = createStyles(({ css }) => ({ + container: css` + width: 100%; + height: 100%; + + .${INIT_NODE} { + padding: 0; + box-sizing: border-box; + width: 320px; + height: 83px; + border: none; + box-shadow: 0 1px 4px 1px rgba(0, 0, 0, 8%); + border-radius: 8px; + cursor: pointer; + z-index: 1; + } + + .${EDGE_SELECT} path { + stroke: #1677ff; + stroke-width: 2; + z-index: 100; + } + + .${EDGE_DANGER} path { + stroke: #f7636e; + stroke-width: 2; + z-index: 100; + } + + .${EDGE_WARNING} path { + stroke: #ef9d3b; + stroke-width: 2; + z-index: 100; + } + + .selectable:focus { + box-shadow: none !important; + } + + .selected { + box-shadow: none !important; + } + `, +})); diff --git a/src/ProFlowController/demos/FlowControllerDemo.tsx b/src/ProFlowController/demos/FlowControllerDemo.tsx index 09ddf5b..29fc2c7 100644 --- a/src/ProFlowController/demos/FlowControllerDemo.tsx +++ b/src/ProFlowController/demos/FlowControllerDemo.tsx @@ -1,8 +1,8 @@ import { createStyles } from 'antd-style'; import { memo } from 'react'; -import { Background, BackgroundVariant } from 'reactflow'; -import ProFlowController from '..'; -import ProFlow from '../../ProFlow'; +// import { Background, BackgroundVariant } from 'reactflow'; +// import ProFlowController from '..'; +// import ProFlow from '../../ProFlow'; const useStyles = createStyles(({ css }) => ({ container: css` @@ -15,10 +15,10 @@ const FlowControllerDemo = memo(() => { const { styles } = useStyles(); return (
- + {/* - + */}
); });