diff --git a/src/BloodGroupNode/styles.ts b/src/BloodGroupNode/styles.ts index 3d7c2be..4f756d6 100644 --- a/src/BloodGroupNode/styles.ts +++ b/src/BloodGroupNode/styles.ts @@ -106,11 +106,20 @@ export const useStyles = createStyles(({ css }) => ({ nodeSelected: css` box-shadow: 0 0 0 3px #1677ff, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; `, + nodeSubSelected: css` + box-shadow: 0 0 0 1px #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%); `, + nodeSubDanger: css` + box-shadow: 0 0 0 1px #f7636e, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, nodeWarning: css` box-shadow: 0 0 0 3px #ef9d3b, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; `, + nodeSubWarning: css` + box-shadow: 0 0 0 1px #ef9d3b, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, nodeDefault: css``, })); diff --git a/src/BloodNode/index.tsx b/src/BloodNode/index.tsx index 0b365b4..d9d5e69 100644 --- a/src/BloodNode/index.tsx +++ b/src/BloodNode/index.tsx @@ -1,4 +1,12 @@ -import { NODE_DANGER, NODE_SELECT, NODE_WARNING, NodeSelect } from '@/ProFlow/constants'; +import { + NODE_DANGER, + NODE_SELECT, + NODE_SUB_DANGER, + NODE_SUB_SELECT, + NODE_SUB_WARNING, + NODE_WARNING, + NodeSelect, +} from '@/ProFlow/constants'; import React from 'react'; import styled from 'styled-components'; import { useStyles } from './styles'; @@ -14,6 +22,10 @@ interface BloodNodeProps { selectType?: NodeSelect; zoom?: number; label?: string; + titleSlot?: { + type: 'left' | 'right'; + value: React.ReactNode; + }; } const zoomNum = (num: number, zoom: number, limitMax?: boolean) => { @@ -33,14 +45,34 @@ export const ArtboardTitle = styled.div<{ zoom: number }>` white-space: nowrap; `; +const TitleSlotLeft = styled.div` + width: 28px; + height: 28px; + margin-left: 8px; +`; + +const TitleSlotRight = styled.div` + width: 28px; + height: 28px; + position: absolute; + right: 13px; + top: 9px; +`; + export function getClsFromSelectType(select: NodeSelect) { switch (select) { case NodeSelect.SELECT: return NODE_SELECT; + case NodeSelect.SUB_SELECT: + return NODE_SUB_SELECT; case NodeSelect.DANGER: return NODE_DANGER; + case NodeSelect.SUB_DANGER: + return NODE_SUB_DANGER; case NodeSelect.WARNING: return NODE_WARNING; + case NodeSelect.SUB_WARNING: + return NODE_SUB_WARNING; default: return 'nodeDefault'; } @@ -54,6 +86,7 @@ const BloodNode: React.FC> = ({ selectType = NodeSelect.SELECT, zoom = 1, label, + titleSlot, }) => { const { styles, cx } = useStyles(); @@ -71,9 +104,17 @@ const BloodNode: React.FC> = ({
{title} - {/* {mainDanger && } - {qualityScore && } */} + {!!titleSlot && !!titleSlot.value && titleSlot.type === 'left' && ( + {titleSlot.value} + )} + {!!titleSlot && !!titleSlot.value && titleSlot.type === 'right' && ( + +
+ {titleSlot.value} +
+ )}
+
{description}
diff --git a/src/BloodNode/styles.ts b/src/BloodNode/styles.ts index 23a1e59..dfb8001 100644 --- a/src/BloodNode/styles.ts +++ b/src/BloodNode/styles.ts @@ -74,11 +74,20 @@ export const useStyles = createStyles(({ css, cx, prefixCls }) => ({ nodeSelected: css` box-shadow: 0 0 0 3px #1677ff, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; `, + nodeSubSelected: css` + box-shadow: 0 0 0 1px #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%); `, + nodeSubDanger: css` + box-shadow: 0 0 0 1px #f7636e, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, nodeWarning: css` box-shadow: 0 0 0 3px #ef9d3b, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; `, + nodeSubWarning: css` + box-shadow: 0 0 0 1px #ef9d3b, 0 1px 4px 1px rgba(0, 0, 0, 8%) !important; + `, nodeDefault: css``, })); diff --git a/src/FlowStoreProvider/demos/FlowStoreProvider.tsx b/src/FlowStoreProvider/demos/FlowStoreProvider.tsx index 05326fb..211d71b 100644 --- a/src/FlowStoreProvider/demos/FlowStoreProvider.tsx +++ b/src/FlowStoreProvider/demos/FlowStoreProvider.tsx @@ -37,7 +37,6 @@ export default () => { { - console.log(flattenNodes); setNodes(flattenNodes); }} > diff --git a/src/ProFlow/constants.tsx b/src/ProFlow/constants.tsx index 84c6371..49369b0 100644 --- a/src/ProFlow/constants.tsx +++ b/src/ProFlow/constants.tsx @@ -1,13 +1,15 @@ -import { ProFlowNode, ProFlowNodeData } from '@/constants'; import { Node } from 'reactflow'; +import { ProFlowNode, ProFlowNodeData } from '../constants'; export enum NodeSelect { SELECT = 'SELECT', + SUB_SELECT = 'SUB_SELECT', DANGER = 'DANGER', + SUB_DANGER = 'SUB_DANGER', WARNING = 'WARNING', + SUB_WARNING = 'SUB_WARNING', DEFAULT = 'DEFAULT', } - export interface InitialNode extends Node { width?: number; height?: number; @@ -47,10 +49,18 @@ export interface NodeMapItem { export type NodeMapping = Record; export const NODE_SELECT = 'nodeSelected'; +export const NODE_SUB_SELECT = 'nodeSubSelected'; export const NODE_DANGER = 'nodeDanger'; +export const NODE_SUB_DANGER = 'nodeSubDanger'; export const NODE_WARNING = 'nodeWarning'; -export const INIT_NODE = 'initialNode'; -export const NODE_WRAP = 'nodeWrap'; +export const NODE_SUB_WARNING = 'nodeSubWarning'; + export const EDGE_SELECT = 'edgeSelected'; +export const EDGE_SUB_SELECT = 'edgeSubSelected'; export const EDGE_DANGER = 'edgeDanger'; +export const EDGE_SUB_DANGER = 'edgeSubDanger'; export const EDGE_WARNING = 'edgeWarning'; +export const EDGE_SUB_WARNING = 'edgeSubWarning'; + +export const INIT_NODE = 'initialNode'; +export const NODE_WRAP = 'nodeWrap'; diff --git a/src/ProFlow/demos/ProFlowDemo.tsx b/src/ProFlow/demos/ProFlowDemo.tsx index 57dae0a..875d52e 100644 --- a/src/ProFlow/demos/ProFlowDemo.tsx +++ b/src/ProFlow/demos/ProFlowDemo.tsx @@ -1,15 +1,53 @@ -import { NodeSelect, ProFlowNode } from '@/index'; +import { EdgeType, NodeSelect, ProFlowNode } from '@/index'; +import { Progress } from 'antd'; import { createStyles } from 'antd-style'; import { memo } from 'react'; +import styled from 'styled-components'; import ProFlow from '..'; const useStyles = createStyles(({ css }) => ({ container: css` width: 100%; height: 600px; + .ant-progress-text { + text-align: center !important; + } `, })); +const ApiScore: React.FC<{ score: number }> = ({ score }) => { + return ( + 60 ? '#30a46c' : '#e5484d'} + format={() => `${score}`} + size={[28, 6]} + /> + ); +}; + +const DangerLogo = styled.div` + width: 28px; + height: 16px; + background: #ffeef1; + border-radius: 7px; + + margin-top: 3px; + display: flex; + justify-content: center; + align-items: center; + img { + width: 8px; + height: 9px; + } +`; + const nodes: ProFlowNode[] = [ { id: 'a1', @@ -22,25 +60,60 @@ const nodes: ProFlowNode[] = [ }, }, { - id: 'a2', - select: NodeSelect.DANGER, + id: 'b1', + select: NodeSelect.SUB_SELECT, data: { - title: 'XXX_API', + title: 'XXX_API_ddddddddddddddddddddddddddddddddddddddddddddddddddddddb1', logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', describe: 'XXX_XXX_XXX_API', + titleSlot: { + type: 'left', + value: ( + + + + ), + }, }, }, { - id: 'b1', - select: NodeSelect.DANGER, + id: 'b2', + select: NodeSelect.SUB_DANGER, + data: { + title: 'XXX_APIddddddddddddddddddddddddddddddddddddddddddddddddddd_b2', + logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', + describe: 'XXX_XXX_XXX_API', + titleSlot: { + type: 'right', + value: , + }, + }, + }, + { + id: 'b3', + select: NodeSelect.SUB_WARNING, + data: { + title: 'XXX_API_b3', + logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', + describe: 'XXX_XXX_XXX_API', + }, + }, + { + id: 'b4', + select: NodeSelect.DEFAULT, data: { - title: 'XXX_API', + title: 'XXX_API_b4', logo: 'https://mdn.alipayobjects.com/huamei_ntgeqc/afts/img/A*kgyiRKi04eUAAAAAAAAAAAAADvuvAQ/original', describe: 'XXX_XXX_XXX_API', }, }, { - id: 'a3', + id: 'c1', select: NodeSelect.WARNING, data: { title: 'XXXX产品', @@ -49,9 +122,9 @@ const nodes: ProFlowNode[] = [ }, }, { - id: 'a4', + id: 'd1', group: true, - select: NodeSelect.WARNING, + select: NodeSelect.SUB_SELECT, label: '456', data: [ { @@ -123,28 +196,68 @@ const nodes: ProFlowNode[] = [ const edges = [ { - id: 'a1-a2', + id: 'a1-b1', source: 'a1', - select: NodeSelect.WARNING, - target: 'a2', + select: NodeSelect.SUB_WARNING, + target: 'b1', + type: EdgeType.default, }, { - id: 'a1-b1', + id: 'a1-b2', + source: 'a1', + select: NodeSelect.SUB_WARNING, + target: 'b2', + type: EdgeType.default, + }, + { + id: 'a1-b3', + source: 'a1', + select: NodeSelect.SUB_DANGER, + target: 'b3', + type: EdgeType.default, + }, + { + id: 'a1-b4', source: 'a1', + select: NodeSelect.SUB_SELECT, + target: 'b4', + type: EdgeType.default, + }, + + { + id: 'b2-c1', + source: 'b2', select: NodeSelect.WARNING, - target: 'b1', + target: 'c1', + type: EdgeType.default, + }, + { + id: 'b3-c1', + source: 'b3', + select: NodeSelect.WARNING, + target: 'c1', + type: EdgeType.default, + }, + { + id: 'b1-c1', + source: 'b1', + select: NodeSelect.WARNING, + target: 'c1', + type: EdgeType.default, }, { - id: 'a2-a3', - source: 'a2', + id: 'b4-c1', + source: 'b4', select: NodeSelect.WARNING, - target: 'a3', + target: 'c1', + type: EdgeType.default, }, { - id: 'a3-a4', - source: 'a3', + id: 'c1-d1', + source: 'c1', select: NodeSelect.WARNING, - target: 'a4', + target: 'd1', + type: EdgeType.default, }, ]; diff --git a/src/ProFlow/helper.tsx b/src/ProFlow/helper.tsx index 17db6b1..d291e77 100644 --- a/src/ProFlow/helper.tsx +++ b/src/ProFlow/helper.tsx @@ -7,6 +7,9 @@ import { Edge, Node, Position } from 'reactflow'; import { EDGE_DANGER, EDGE_SELECT, + EDGE_SUB_DANGER, + EDGE_SUB_SELECT, + EDGE_SUB_WARNING, EDGE_WARNING, INIT_NODE, InitialNode, @@ -97,27 +100,58 @@ function getEdgeClsFromNodeSelect(select: NodeSelect) { switch (select) { case NodeSelect.SELECT: return EDGE_SELECT; + case NodeSelect.SUB_SELECT: + return EDGE_SUB_SELECT; case NodeSelect.DANGER: return EDGE_DANGER; + case NodeSelect.SUB_DANGER: + return EDGE_SUB_DANGER; case NodeSelect.WARNING: return EDGE_WARNING; + case NodeSelect.SUB_WARNING: + return EDGE_SUB_WARNING; default: return 'edgeDefault'; } } +function getEdgeLevel(select: NodeSelect) { + switch (select) { + case NodeSelect.SELECT: + return 6; + case NodeSelect.SUB_SELECT: + return 5; + case NodeSelect.DANGER: + return 4; + case NodeSelect.SUB_DANGER: + return 3; + case NodeSelect.WARNING: + return 2; + case NodeSelect.SUB_WARNING: + return 1; + default: + return 0; + } +} + export function getRenderEdges(edges: ProFlowEdge[]) { - return edges.map((edge) => { - const { source, target, select = NodeSelect.DEFAULT } = edge; - - return { - id: `${source}-${target}`, - source, - target, - type: 'radiusEdge', - className: getEdgeClsFromNodeSelect(select), - }; - }); + return edges + .sort((a, b) => { + const aLevel = a.select ? getEdgeLevel(a.select) : 0; + const bLevel = b.select ? getEdgeLevel(b.select) : 0; + return aLevel - bLevel; + }) + .map((edge) => { + const { source, target, select = NodeSelect.DEFAULT } = edge; + + return { + id: `${source}-${target}`, + source, + target, + type: 'smoothstep', + className: getEdgeClsFromNodeSelect(select), + }; + }); } export const getRenderData = ( @@ -135,8 +169,6 @@ export const getRenderData = ( const node = mapping[id]; const { select = NodeSelect.DEFAULT } = node; - console.log(node.zoom); - renderNodes.push({ sourcePosition: Position.Right, targetPosition: Position.Left, @@ -164,6 +196,7 @@ export const getRenderData = ( selectType={select} zoom={node.zoom} label={node.label} + titleSlot={(node.data! as ProFlowNodeData).titleSlot} /> ), }, diff --git a/src/ProFlow/index.tsx b/src/ProFlow/index.tsx index 2bdb718..ad3588c 100644 --- a/src/ProFlow/index.tsx +++ b/src/ProFlow/index.tsx @@ -8,7 +8,7 @@ import ReactFlow, { useViewport, } from 'reactflow'; import 'reactflow/dist/style.css'; -import { ProFlowController, ProFlowProps, RadiusEdge } from '../index'; +import { ProFlowController, ProFlowProps } from '../index'; import { convertMappingFrom, getRenderData } from './helper'; import { useStyles } from './styles'; @@ -84,14 +84,15 @@ const Flow: React.FC> = (props) => { onNodeClick={handleNodeClick} nodes={renderData.nodes} edges={renderData.edges} - edgeTypes={{ - radiusEdge: RadiusEdge, - }} + // edgeTypes={{ + // // radiusEdge: RadiusEdge, + // // defaultEdge: DefaultEdge, + // }} panOnScroll fitView minZoom={MIN_ZOOM} > - {miniMap && } + {miniMap && } ); diff --git a/src/ProFlow/styles.tsx b/src/ProFlow/styles.tsx index 93f1a7e..970f0ce 100644 --- a/src/ProFlow/styles.tsx +++ b/src/ProFlow/styles.tsx @@ -1,5 +1,13 @@ import { createStyles } from 'antd-style'; -import { EDGE_DANGER, EDGE_SELECT, EDGE_WARNING, INIT_NODE } from './constants'; +import { + EDGE_DANGER, + EDGE_SELECT, + EDGE_SUB_DANGER, + EDGE_SUB_SELECT, + EDGE_SUB_WARNING, + EDGE_WARNING, + INIT_NODE, +} from './constants'; export const useStyles = createStyles(({ css }) => ({ container: css` @@ -28,18 +36,36 @@ export const useStyles = createStyles(({ css }) => ({ z-index: 100; } + .${EDGE_SUB_SELECT} path { + stroke: #1677ff; + stroke-width: 1; + z-index: 100; + } + .${EDGE_DANGER} path { stroke: #f7636e; stroke-width: 2; z-index: 100; } + .${EDGE_SUB_DANGER} path { + stroke: #f7636e; + stroke-width: 1; + z-index: 100; + } + .${EDGE_WARNING} path { stroke: #ef9d3b; stroke-width: 2; z-index: 100; } + .${EDGE_SUB_WARNING} path { + stroke: #ef9d3b; + stroke-width: 1; + z-index: 100; + } + .selectable:focus { box-shadow: none !important; } diff --git a/src/ProFlowController/index.tsx b/src/ProFlowController/index.tsx index b42bae1..018ea13 100644 --- a/src/ProFlowController/index.tsx +++ b/src/ProFlowController/index.tsx @@ -40,10 +40,11 @@ const useStyles = createStyles(({ css }) => ({ interface ProFlowControllerProps { visible?: boolean; + className?: string; } const ProFlowController: React.FC> = (props) => { - const { visible = false } = props; + const { visible = false, className = '' } = props; const reactFlow = useReactFlow(); const { zoom } = useViewport(); const { styles, cx } = useStyles(); @@ -67,7 +68,7 @@ const ProFlowController: React.FC> = (props) => }; return ( -
+