feat(flowEditor): 实现节点粘贴功能并优化事件列表获取逻辑

master
钟良源 3 months ago
parent 37ead877ec
commit 052f454bef

@ -26,7 +26,6 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
selected,
data
}) => {
const [options, setOptions] = useState([]);
const [isOpen, setIsOpen] = useState(false);
const [selectedValue, setSelectedValue] = useState('');
const dropdownRef = useRef<HTMLDivElement>(null);
@ -39,7 +38,7 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
targetPosition,
borderRadius: 8 // 设置圆角半径
});
const { info } = useSelector((state: any) => state.ideContainer);
const { info, eventTopicList } = useSelector((state: any) => state.ideContainer);
// 从数据中获取悬停状态
const hovered = data?.hovered || false;
@ -69,19 +68,6 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
}));
};
const getEventList = async () => {
const res: any = await getTopicList(info.id);
if (res.code === 200) {
setOptions(res.data.map(v => {
return { label: v.eventName, value: v.topic };
}));
}
};
useEffect(() => {
getEventList();
}, [displayData]);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
@ -163,7 +149,7 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
overflowY: 'auto'
}}
>
{options.map((option: { value: string; label: string }) => (
{eventTopicList.map((option: { value: string; label: string }) => (
<div
key={option.value}
onClick={() => handleSelect(option)}

@ -86,6 +86,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini
editNode,
editEdge,
copyNode,
pasteNode, // 添加粘贴节点功能
// Node operations
addNodeOnEdge,
@ -200,11 +201,46 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini
// 点击画布其他区域关闭菜单
const onPaneClick = useCallback(() => {
setMenu(null);
// 关闭添加节点菜单
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
}, [setMenu]);
// 添加处理粘贴事件的函数
const handlePasteNode = useCallback((event: ClipboardEvent) => {
// 检查是否是粘贴操作且在画布区域内
if (event.clipboardData?.getData('text') === 'paste-node' && menu?.type === 'pane' && menu.position) {
pasteNode(menu.position);
setMenu(null);
}
}, [menu, pasteNode]);
// 添加键盘事件监听
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// 检查是否按下了 Ctrl+V (Windows/Linux) 或 Cmd+V (Mac)
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
// 触发自定义粘贴事件
const pasteEvent = new ClipboardEvent('paste', {
clipboardData: new DataTransfer()
});
pasteEvent.clipboardData?.setData('text', 'paste-node');
document.dispatchEvent(pasteEvent);
}
};
// 为画布添加键盘事件监听
const canvasElement = reactFlowWrapper.current;
if (canvasElement) {
canvasElement.addEventListener('keydown', handleKeyDown);
document.addEventListener('paste', handlePasteNode);
}
return () => {
if (canvasElement) {
canvasElement.removeEventListener('keydown', handleKeyDown);
}
document.removeEventListener('paste', handlePasteNode);
};
}, [handlePasteNode]);
// 监听边的变化,处理添加节点的触发
useEffect(() => {
const edgeToAddNode = edges.find(edge => edge.data?.addNodeTrigger);
@ -243,73 +279,80 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini
}
return (
<HistoryProvider
initialNodes={nodes}
initialEdges={edges}
onHistoryChange={(newNodes: Node[], newEdges: Edge[]) => {
setNodes(newNodes);
setEdges(newEdges);
}}
<div
ref={reactFlowWrapper}
style={{ width: '100%', height: '100%' }}
onContextMenu={(e) => e.preventDefault()}
tabIndex={0} // 使div可获得焦点以接收键盘事件
>
<FlowEditorMain
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
setNodes={setNodes}
setEdges={setEdges}
useDefault={useDefault}
reactFlowInstance={reactFlowInstance}
reactFlowWrapper={reactFlowWrapper}
menu={menu}
setMenu={setMenu}
editingNode={editingNode}
setEditingNode={setEditingNode}
isEditModalOpen={isEditModalOpen}
setIsEditModalOpen={setIsEditModalOpen}
isDelete={isDelete}
setIsDelete={setIsDelete}
edgeForNodeAdd={edgeForNodeAdd}
setEdgeForNodeAdd={setEdgeForNodeAdd}
positionForNodeAdd={positionForNodeAdd}
setPositionForNodeAdd={setPositionForNodeAdd}
isRunning={isRunning}
initialData={initialData}
canvasDataMap={canvasDataMap}
// Event handlers
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onReconnect={onReconnect}
onDragOver={onDragOver}
onDrop={onDrop}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeDragStop}
onNodeContextMenu={onNodeContextMenu}
onNodeDoubleClick={onNodeDoubleClick}
onEdgeContextMenu={onEdgeContextMenu}
onPaneContextMenu={onPaneContextMenu}
onPaneClick={onPaneClick}
// Menu handlers
closeEditModal={closeEditModal}
saveNodeEdit={saveNodeEdit}
deleteNode={deleteNode}
deleteEdge={deleteEdge}
editNode={editNode}
editEdge={editEdge}
copyNode={copyNode}
// Node operations
addNodeOnEdge={addNodeOnEdge}
addNodeOnPane={addNodeOnPane}
handleAddNode={handleAddNode}
// Actions
saveFlowDataToServer={saveFlowDataToServer}
handleRun={handleRun}
/>
</HistoryProvider>
<HistoryProvider
initialNodes={nodes}
initialEdges={edges}
onHistoryChange={(newNodes: Node[], newEdges: Edge[]) => {
setNodes(newNodes);
setEdges(newEdges);
}}
>
<FlowEditorMain
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
setNodes={setNodes}
setEdges={setEdges}
useDefault={useDefault}
reactFlowInstance={reactFlowInstance}
reactFlowWrapper={reactFlowWrapper}
menu={menu}
setMenu={setMenu}
editingNode={editingNode}
setEditingNode={setEditingNode}
isEditModalOpen={isEditModalOpen}
setIsEditModalOpen={setIsEditModalOpen}
isDelete={isDelete}
setIsDelete={setIsDelete}
edgeForNodeAdd={edgeForNodeAdd}
setEdgeForNodeAdd={setEdgeForNodeAdd}
positionForNodeAdd={positionForNodeAdd}
setPositionForNodeAdd={setPositionForNodeAdd}
isRunning={isRunning}
initialData={initialData}
canvasDataMap={canvasDataMap}
// Event handlers
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onReconnect={onReconnect}
onDragOver={onDragOver}
onDrop={onDrop}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeDragStop}
onNodeContextMenu={onNodeContextMenu}
onNodeDoubleClick={onNodeDoubleClick}
onEdgeContextMenu={onEdgeContextMenu}
onPaneContextMenu={onPaneContextMenu}
onPaneClick={onPaneClick}
// Menu handlers
closeEditModal={closeEditModal}
saveNodeEdit={saveNodeEdit}
deleteNode={deleteNode}
deleteEdge={deleteEdge}
editNode={editNode}
editEdge={editEdge}
copyNode={copyNode}
// Node operations
addNodeOnEdge={addNodeOnEdge}
addNodeOnPane={addNodeOnPane}
handleAddNode={handleAddNode}
// Actions
saveFlowDataToServer={saveFlowDataToServer}
handleRun={handleRun}
/>
</HistoryProvider>
</div>
);
};

@ -1,18 +1,33 @@
import React, { useEffect, useState } from 'react';
import FlowEditor from '@/pages/flowEditor/index';
import { useSelector } from 'react-redux';
import { getAppEventData, getAppEventList } from '@/api/appEvent';
import { useSelector, useDispatch } from 'react-redux';
import { getAppEventList } from '@/api/appEvent';
import { getTopicList } from '@/api/event';
import { updateEventTopicList } from '@/store/ideContainer';
const ApplicationContainer = () => {
const { info } = useSelector((state: any) => state.ideContainer);
const [appFlowList, setAppFlowList] = useState([]);
const dispatch = useDispatch();
const getAppFlowList = async () => {
const res: any = await getAppEventList(info.id);
if (res.code === 200) setAppFlowList(res.data);
};
const getEventList = async () => {
const res: any = await getTopicList(info.id);
if (res.code === 200) {
dispatch(updateEventTopicList(res.data.map(v => {
return { label: v.eventName, value: v.topic };
})));
}
};
useEffect(() => {
getEventList();
getAppFlowList();
}, []);

@ -9,6 +9,7 @@ interface IDEContainerState {
projectComponentData: any;
currentAppData: any;
eventList: any;
eventTopicList: any;
logBarStatus?: boolean;
socketId: string;
nodeStatusMap: Record<string, string>; // 节点状态映射
@ -24,6 +25,7 @@ const initialState: IDEContainerState = {
projectComponentData: {}, // 工程下的组件列表
currentAppData: {}, // 当前选中的应用数据
eventList: [], // 工程下的事件列表
eventTopicList: [], // 应用编排使用的事件名和topic列表
logBarStatus: false,
socketId: '', // 工程的socketId
nodeStatusMap: {}, // 初始化节点状态映射
@ -56,6 +58,9 @@ const ideContainerSlice = createSlice({
updateEventList(state, action) {
state.eventList = action.payload;
},
updateEventTopicList(state, action) {
state.eventTopicList = action.payload;
},
updateLogBarStatus(state, action) {
state.logBarStatus = action.payload;
},
@ -87,6 +92,7 @@ export const {
updateProjectComponentData,
updateCurrentAppData,
updateEventList,
updateEventTopicList,
updateLogBarStatus,
updateSocketId,
updateNodeStatus,

Loading…
Cancel
Save