This commit is contained in:
dengqichen 2025-10-21 10:31:09 +08:00
parent a8c512eee6
commit 051709ed2a
3 changed files with 135 additions and 146 deletions

View File

@ -26,6 +26,7 @@ interface FlowCanvasProps {
onEdgeClick?: (event: React.MouseEvent, edge: any) => void;
onDrop?: (event: React.DragEvent) => void;
onDragOver?: (event: React.DragEvent) => void;
onViewportChange?: () => void;
className?: string;
}
@ -38,6 +39,7 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({
onEdgeClick,
onDrop,
onDragOver,
onViewportChange,
className = ''
}) => {
const [nodes, , onNodesStateChange] = useNodesState(initialNodes);
@ -133,6 +135,7 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({
onEdgeClick={onEdgeClick}
onDrop={handleDrop}
onDragOver={handleDragOver}
onMove={onViewportChange}
nodeTypes={nodeTypes}
isValidConnection={isValidConnection}
fitView

View File

@ -1,11 +1,10 @@
import React from 'react';
import { Button, Space, Divider, Tooltip } from 'antd';
import { Button, Divider, Tooltip } from 'antd';
import {
SaveOutlined,
UndoOutlined,
RedoOutlined,
CopyOutlined,
ScissorOutlined,
DeleteOutlined,
ZoomInOutlined,
ZoomOutOutlined,
@ -20,8 +19,6 @@ interface WorkflowToolbarProps {
onUndo?: () => void;
onRedo?: () => void;
onCopy?: () => void;
onCut?: () => void;
onPaste?: () => void;
onDelete?: () => void;
onZoomIn?: () => void;
onZoomOut?: () => void;
@ -40,8 +37,6 @@ const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
onUndo,
onRedo,
onCopy,
onCut,
onPaste,
onDelete,
onZoomIn,
onZoomOut,
@ -67,7 +62,7 @@ const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)'
}}
>
{/* 左侧:标题和返回按钮 */}
{/* 左侧:返回按钮和标题 */}
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<Tooltip title="返回列表">
<Button
@ -78,154 +73,124 @@ const WorkflowToolbar: React.FC<WorkflowToolbarProps> = ({
/>
</Tooltip>
<Divider type="vertical" />
<div>
<h2 style={{
margin: 0,
fontSize: '16px',
fontWeight: '600',
color: '#374151'
}}>
{title}
</h2>
<div style={{
fontSize: '12px',
color: '#6b7280',
marginTop: '2px'
}}>
React Flow
</div>
</div>
<h2 style={{
margin: 0,
fontSize: '16px',
fontWeight: '600',
color: '#374151'
}}>
{title}
</h2>
</div>
{/* 中间:主要操作按钮 */}
<div style={{ display: 'flex', alignItems: 'center' }}>
<Space size={4}>
{/* 保存 */}
<Tooltip title="保存工作流">
<Button
type="primary"
icon={<SaveOutlined />}
onClick={onSave}
size="small"
>
</Button>
</Tooltip>
{/* 右侧:操作按钮区域 */}
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
{/* 撤销/重做 */}
<Tooltip title="撤销">
<Button
type="text"
icon={<UndoOutlined />}
onClick={onUndo}
disabled={!canUndo}
size="small"
/>
</Tooltip>
<Tooltip title="重做">
<Button
type="text"
icon={<RedoOutlined />}
onClick={onRedo}
disabled={!canRedo}
size="small"
/>
</Tooltip>
<Divider type="vertical" />
<Divider type="vertical" />
{/* 撤销/重做 */}
<Tooltip title="撤销">
<Button
type="text"
icon={<UndoOutlined />}
onClick={onUndo}
disabled={!canUndo}
size="small"
/>
</Tooltip>
<Tooltip title="重做">
<Button
type="text"
icon={<RedoOutlined />}
onClick={onRedo}
disabled={!canRedo}
size="small"
/>
</Tooltip>
{/* 编辑操作 */}
<Tooltip title="复制">
<Button
type="text"
icon={<CopyOutlined />}
onClick={onCopy}
size="small"
/>
</Tooltip>
<Tooltip title="删除选中">
<Button
type="text"
icon={<DeleteOutlined />}
onClick={onDelete}
size="small"
style={{ color: '#ef4444' }}
/>
</Tooltip>
<Tooltip title="全选">
<Button
type="text"
icon={<SelectOutlined />}
onClick={onSelectAll}
size="small"
/>
</Tooltip>
<Divider type="vertical" />
<Divider type="vertical" />
{/* 编辑操作 */}
<Tooltip title="复制">
<Button
type="text"
icon={<CopyOutlined />}
onClick={onCopy}
size="small"
/>
</Tooltip>
<Tooltip title="剪切">
<Button
type="text"
icon={<ScissorOutlined />}
onClick={onCut}
size="small"
/>
</Tooltip>
<Tooltip title="删除选中">
<Button
type="text"
icon={<DeleteOutlined />}
onClick={onDelete}
size="small"
style={{ color: '#ef4444' }}
/>
</Tooltip>
<Tooltip title="全选">
<Button
type="text"
icon={<SelectOutlined />}
onClick={onSelectAll}
size="small"
/>
</Tooltip>
{/* 视图操作 */}
<Tooltip title="放大">
<Button
type="text"
icon={<ZoomInOutlined />}
onClick={onZoomIn}
size="small"
/>
</Tooltip>
<Tooltip title="缩小">
<Button
type="text"
icon={<ZoomOutOutlined />}
onClick={onZoomOut}
size="small"
/>
</Tooltip>
<Tooltip title="适应视图">
<Button
type="text"
icon={<ExpandOutlined />}
onClick={onFitView}
size="small"
/>
</Tooltip>
<Divider type="vertical" />
<Divider type="vertical" />
{/* 视图操作 */}
<Tooltip title="放大">
<Button
type="text"
icon={<ZoomInOutlined />}
onClick={onZoomIn}
size="small"
/>
</Tooltip>
<Tooltip title="缩小">
<Button
type="text"
icon={<ZoomOutOutlined />}
onClick={onZoomOut}
size="small"
/>
</Tooltip>
<Tooltip title="适应视图">
<Button
type="text"
icon={<ExpandOutlined />}
onClick={onFitView}
size="small"
/>
</Tooltip>
</Space>
</div>
{/* 右侧:状态信息 */}
<div style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
fontSize: '12px',
color: '#6b7280'
}}>
{/* 缩放比例显示 */}
<div style={{
background: '#f3f4f6',
padding: '4px 8px',
borderRadius: '4px',
fontFamily: 'monospace'
fontSize: '12px',
color: '#6b7280',
fontFamily: 'monospace',
minWidth: '70px',
textAlign: 'center'
}}>
: {Math.round(zoom * 100)}%
</div>
<div style={{
background: '#ecfdf5',
color: '#065f46',
padding: '4px 8px',
borderRadius: '4px',
fontWeight: '500'
}}>
React Flow
{Math.round(zoom * 100)}%
</div>
<Divider type="vertical" />
{/* 保存按钮(最右侧) */}
<Tooltip title="保存工作流">
<Button
type="primary"
icon={<SaveOutlined />}
onClick={onSave}
size="small"
>
</Button>
</Tooltip>
</div>
</div>
);

View File

@ -34,6 +34,7 @@ const WorkflowDesignInner: React.FC = () => {
} = useReactFlow();
const [workflowTitle, setWorkflowTitle] = useState('新建工作流');
const [currentZoom, setCurrentZoom] = useState(1); // 当前缩放比例
const reactFlowWrapper = useRef<HTMLDivElement>(null);
// 当前工作流ID
@ -67,6 +68,11 @@ const WorkflowDesignInner: React.FC = () => {
loadData();
}, [currentWorkflowId, loadWorkflow, setNodes, setEdges]);
// 初始化缩放比例
useEffect(() => {
setCurrentZoom(getZoom());
}, [getZoom]);
// 自动适应视图
useEffect(() => {
// 延迟执行fitView以确保节点已渲染
@ -77,10 +83,12 @@ const WorkflowDesignInner: React.FC = () => {
minZoom: 1.0, // 最小缩放100%
maxZoom: 1.0 // 最大缩放100%确保默认100%
});
// 更新zoom显示
setTimeout(() => setCurrentZoom(getZoom()), 850);
}, 100);
return () => clearTimeout(timer);
}, [fitView]);
}, [fitView, getZoom]);
// 初始化示例节点 - 优化位置和布局
const initialNodes: FlowNode[] = [
@ -217,15 +225,21 @@ const WorkflowDesignInner: React.FC = () => {
const handleFitView = useCallback(() => {
fitView({ padding: 0.2, duration: 800 });
}, [fitView]);
// 延迟更新zoom值以获取最新的缩放比例
setTimeout(() => setCurrentZoom(getZoom()), 850);
}, [fitView, getZoom]);
const handleZoomIn = useCallback(() => {
zoomIn({ duration: 300 });
}, [zoomIn]);
// 延迟更新zoom值以获取最新的缩放比例
setTimeout(() => setCurrentZoom(getZoom()), 350);
}, [zoomIn, getZoom]);
const handleZoomOut = useCallback(() => {
zoomOut({ duration: 300 });
}, [zoomOut]);
// 延迟更新zoom值以获取最新的缩放比例
setTimeout(() => setCurrentZoom(getZoom()), 350);
}, [zoomOut, getZoom]);
// 处理节点拖拽放置 - 使用官方推荐的screenToFlowPosition方法
const handleDrop = useCallback((event: React.DragEvent) => {
@ -352,6 +366,12 @@ const WorkflowDesignInner: React.FC = () => {
setConfigEdge(null);
}, []);
// 监听视图变化(缩放、平移等)
const handleViewportChange = useCallback(() => {
const zoom = getZoom();
setCurrentZoom(zoom);
}, [getZoom]);
return (
<div
className="workflow-design-container"
@ -375,7 +395,7 @@ const WorkflowDesignInner: React.FC = () => {
onFitView={handleFitView}
canUndo={false}
canRedo={false}
zoom={getZoom()}
zoom={currentZoom}
/>
{/* 主要内容区域 */}
@ -394,6 +414,7 @@ const WorkflowDesignInner: React.FC = () => {
onNodeClick={handleNodeClick}
onEdgeClick={handleEdgeClick}
onDrop={handleDrop}
onViewportChange={handleViewportChange}
className="workflow-canvas"
/>
</div>