deploy-ease-platform/frontend/src/pages/Workflow/Design/components/CustomEdge.tsx
dengqichen cec0962afd 1
2025-10-22 14:27:22 +08:00

112 lines
3.4 KiB
TypeScript

import React, { useState, useMemo } from 'react';
import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath, useReactFlow } from '@xyflow/react';
import type { FlowNode } from '../types';
import { convertToDisplayName } from '@/utils/workflow/variableConversion';
/**
* 自定义边组件
* 支持hover高亮和样式优化
*/
const CustomEdge: React.FC<EdgeProps> = ({
id,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
style = {},
markerEnd,
label,
selected,
}) => {
const [isHovered, setIsHovered] = useState(false);
const { getNodes } = useReactFlow();
// 将 label 中的 UUID 转换为节点名
const displayLabel = useMemo(() => {
if (!label || typeof label !== 'string') {
return label;
}
const allNodes = getNodes() as FlowNode[];
return convertToDisplayName(label, allNodes);
}, [label, getNodes]);
const [edgePath, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
// 根据状态确定样式
const edgeStyle = {
...style,
stroke: selected ? '#3b82f6' : isHovered ? '#64748b' : '#94a3b8',
strokeWidth: selected ? 3 : isHovered ? 2.5 : 2,
transition: 'all 0.2s ease',
};
const markerEndStyle = (() => {
if (!markerEnd || typeof markerEnd !== 'object') return markerEnd;
if (selected) return { ...markerEnd, color: '#3b82f6' };
if (isHovered) return { ...markerEnd, color: '#64748b' };
return markerEnd;
})();
return (
<>
<BaseEdge
id={id}
path={edgePath}
style={edgeStyle}
markerEnd={markerEndStyle}
/>
{/* 增加点击区域 */}
<path
d={edgePath}
fill="none"
stroke="transparent"
strokeWidth={20}
style={{ cursor: 'pointer' }}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
/>
{/* 边标签 */}
{displayLabel && (
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
fontSize: '12px',
fontWeight: '500',
color: selected ? '#3b82f6' : '#64748b',
background: 'white',
padding: '4px 10px',
borderRadius: '6px',
border: `1px solid ${selected ? '#3b82f6' : '#e5e7eb'}`,
boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
pointerEvents: 'all',
cursor: 'pointer',
transition: 'all 0.2s ease',
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{displayLabel}
</div>
</EdgeLabelRenderer>
)}
</>
);
};
export default CustomEdge;