You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
flow-playform-react/src/hooks/useFlowEditorState.ts

153 lines
4.4 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useState, useRef, useEffect, useMemo } from 'react';
import { Node, Edge } from '@xyflow/react';
import { debounce } from 'lodash';
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
import { updateCanvasDataMap } from '@/store/ideContainer';
import { getCurrentAppKey } from '@/utils/flow/runtime';
import { Dispatch } from 'redux';
export const useFlowEditorState = (initialData?: any, readOnly?: boolean) => {
const [nodes, setNodes] = useState<Node[]>([]);
const [edges, setEdges] = useState<Edge[]>([]);
// 使用 shallowEqual 比较器来避免不必要的重新渲染
const ideContainerState = useSelector(
(state: any) => ({
canvasDataMap: state.ideContainer.canvasDataMap,
appRuntimeData: state.ideContainer.appRuntimeData,
currentAppData: state.ideContainer.currentAppData,
}),
shallowEqual
);
const { canvasDataMap, appRuntimeData, currentAppData } = ideContainerState;
const dispatch = useDispatch();
// 获取当前应用的运行状态
const currentAppKey = getCurrentAppKey(currentAppData);
const currentAppIsRunning =
currentAppKey && appRuntimeData[currentAppKey]
? appRuntimeData[currentAppKey].isRunning
: false;
// 添加编辑弹窗相关状态
const [editingNode, setEditingNode] = useState<Node | null>(null);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [isDelete, setIsDelete] = useState(false);
// 添加节点选择弹窗状态
const [edgeForNodeAdd, setEdgeForNodeAdd] = useState<Edge | null>(null);
const [positionForNodeAdd, setPositionForNodeAdd] = useState<{
x: number;
y: number;
} | null>(null);
// 在组件顶部添加历史记录相关状态
const [historyInitialized, setHistoryInitialized] = useState(false);
const historyTimeoutRef = useRef<NodeJS.Timeout | null>(null);
// 更新节点状态将从store获取的状态应用到节点上
useEffect(() => {
// 获取当前应用对应的节点状态映射
const currentNodeStatusMap =
currentAppKey && appRuntimeData[currentAppKey]
? appRuntimeData[currentAppKey].nodeStatusMap
: {};
// 检查 initialData 中是否包含节点状态(用于查看历史实例)
const hasInitialDataStatus =
initialData?.components &&
Object.values(initialData.components).some((comp: any) => comp.status);
setNodes((prevNodes) => {
return prevNodes.map((node) => {
// 如果是只读模式(历史实例查看),优先使用节点自身的历史状态
// 如果是正常运行模式,只使用运行时状态
let nodeStatus = 'waiting';
let showStatus = false;
if (readOnly) {
// 只读模式:使用历史状态
nodeStatus = (node.data.status as string) || 'waiting';
showStatus =
(hasInitialDataStatus as boolean) ||
(node.data.isStatusVisible as boolean) ||
false;
} else {
// 正常模式:只使用运行时状态
nodeStatus = currentNodeStatusMap[node.id] || 'waiting';
showStatus = currentAppIsRunning;
}
return {
...node,
data: {
...node.data,
status: nodeStatus,
isStatusVisible: showStatus,
},
};
});
});
}, [
appRuntimeData,
currentAppKey,
currentAppIsRunning,
initialData?.id,
initialData?.components,
nodes.length,
readOnly,
]);
const updateCanvasDataMapDebounced = useRef(
debounce(
(
dispatch: Dispatch<any>,
canvasDataMap: any,
id: string,
nodes: Node[],
edges: Edge[]
) => {
dispatch(
updateCanvasDataMap({
...canvasDataMap,
[id]: { nodes, edges },
})
);
},
500
)
).current;
return {
// State values
nodes,
setNodes,
edges,
setEdges,
canvasDataMap,
editingNode,
setEditingNode,
isEditModalOpen,
setIsEditModalOpen,
isDelete,
setIsDelete,
edgeForNodeAdd,
setEdgeForNodeAdd,
positionForNodeAdd,
setPositionForNodeAdd,
isRunning: currentAppIsRunning, // 使用当前应用的运行状态
historyInitialized,
setHistoryInitialized,
historyTimeoutRef,
updateCanvasDataMapDebounced,
// Redux
dispatch,
// Initial data
initialData: initialData,
};
};