1
This commit is contained in:
parent
a8c512eee6
commit
051709ed2a
@ -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
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user