|
|
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,
|
|
|
};
|
|
|
};
|