feat(flow): 添加节点状态管理和历史实例查看功能

master
钟良源 1 week ago
parent 88b3f90138
commit 5a06269e1d

@ -48,6 +48,7 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
const [runtimeLogs, setRuntimeLogs] = useState<LogMessage[]>([]); const [runtimeLogs, setRuntimeLogs] = useState<LogMessage[]>([]);
const [runtimeData, setRuntimeData] = useState<RuntimeData>({}); const [runtimeData, setRuntimeData] = useState<RuntimeData>({});
const [flowData, setFlowData] = useState<any>(null); // 流程数据 const [flowData, setFlowData] = useState<any>(null); // 流程数据
const [nodeStatusMap, setNodeStatusMap] = useState<Record<string, string>>({}); // 节点状态映射
const [loading, setLoading] = useState(false); // 加载状态 const [loading, setLoading] = useState(false); // 加载状态
const resizeBoxRef = useRef<HTMLDivElement>(null); const resizeBoxRef = useRef<HTMLDivElement>(null);
const flowDataRef = useRef<any>(null); // 使用 ref 来存储 flowData避免重复设置 const flowDataRef = useRef<any>(null); // 使用 ref 来存储 flowData避免重复设置
@ -111,6 +112,8 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
} }
}; };
console.log('InstanceCanvas - 转换后的 flowData:', newFlowData);
// 只在数据真正变化时才更新 // 只在数据真正变化时才更新
if (!flowDataRef.current) { if (!flowDataRef.current) {
flowDataRef.current = newFlowData; flowDataRef.current = newFlowData;
@ -118,7 +121,7 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
} }
} }
// 处理运行日志 // 处理运行日志和节点状态
if (res.data.main?.nodeLogs && Array.isArray(res.data.main.nodeLogs) && res.data.main.nodeLogs.length > 0) { if (res.data.main?.nodeLogs && Array.isArray(res.data.main.nodeLogs) && res.data.main.nodeLogs.length > 0) {
const logs = res.data.main.nodeLogs.map((log: any, index: number) => ({ const logs = res.data.main.nodeLogs.map((log: any, index: number) => ({
id: index, id: index,
@ -131,6 +134,20 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
state: log.state state: log.state
})); }));
setRuntimeLogs(logs); setRuntimeLogs(logs);
// 构建节点状态映射
const statusMap: Record<string, string> = {};
res.data.main.nodeLogs.forEach((log: any) => {
// state: 1=成功(success), 0=运行中(running), -1=失败(failed)
if (log.state === 1) {
statusMap[log.nodeId] = 'success';
} else if (log.state === -1) {
statusMap[log.nodeId] = 'failed';
} else if (log.state === 0) {
statusMap[log.nodeId] = 'running';
}
});
setNodeStatusMap(statusMap);
} }
// 处理运行数据input/output // 处理运行数据input/output
@ -198,6 +215,40 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
} }
}, []); }, []);
// 使用 useMemo 创建带有节点状态的 flowData
const flowDataWithStatus = useMemo(() => {
if (!flowData || Object.keys(nodeStatusMap).length === 0) {
return flowData;
}
console.log('InstanceCanvas - 注入状态前的 flowData:', flowData);
console.log('InstanceCanvas - 要注入的状态映射:', nodeStatusMap);
// 深拷贝 flowData 并注入节点状态
const componentsWithStatus = { ...flowData.components };
Object.keys(nodeStatusMap).forEach((nodeId) => {
if (componentsWithStatus[nodeId]) {
componentsWithStatus[nodeId] = {
...componentsWithStatus[nodeId],
status: nodeStatusMap[nodeId],
isStatusVisible: true // 显示状态指示器
};
}
});
const result = {
...flowData,
components: componentsWithStatus,
main: {
...flowData.main,
components: componentsWithStatus
}
};
console.log('InstanceCanvas - 注入状态后的 flowData:', result);
return result;
}, [flowData, nodeStatusMap]);
// 渲染运行日志内容 // 渲染运行日志内容
const renderRuntimeLogs = () => { const renderRuntimeLogs = () => {
return ( return (
@ -339,9 +390,9 @@ const InstanceCanvas: React.FC<InstanceCanvasProps> = ({ instanceData, title, on
<Spin size={40} /> <Spin size={40} />
<span style={{ marginTop: '16px', color: 'var(--color-text-3)' }}>...</span> <span style={{ marginTop: '16px', color: 'var(--color-text-3)' }}>...</span>
</div> </div>
) : flowData ? ( ) : flowDataWithStatus ? (
<MemoizedFlowEditor <MemoizedFlowEditor
flowData={flowData} flowData={flowDataWithStatus}
instanceId={instanceData?.id || 'instance-canvas'} instanceId={instanceData?.id || 'instance-canvas'}
/> />
) : ( ) : (

@ -57,18 +57,28 @@ export const useFlowEditorState = (initialData?: any) => {
? appRuntimeData[currentAppKey].nodeStatusMap ? appRuntimeData[currentAppKey].nodeStatusMap
: {}; : {};
// 检查 initialData 中是否包含节点状态(用于查看历史实例)
const hasInitialDataStatus = initialData?.components &&
Object.values(initialData.components).some((comp: any) => comp.status);
setNodes(prevNodes =>{ setNodes(prevNodes =>{
return prevNodes.map(node => ({ return prevNodes.map(node => {
// 优先使用运行时状态,其次使用节点自身的状态(历史实例),最后默认为 waiting
const nodeStatus = currentNodeStatusMap[node.id] || node.data.status || 'waiting';
return {
...node, ...node,
data: { data: {
...node.data, ...node.data,
status: currentNodeStatusMap[node.id] || 'waiting', status: nodeStatus,
isStatusVisible: currentAppIsRunning // 只有在运行时才显示状态指示器 // 在运行时或有历史状态时显示状态指示器
isStatusVisible: currentAppIsRunning || hasInitialDataStatus || node.data.isStatusVisible
} }
})) };
});
}); });
}, [appRuntimeData, currentAppKey, currentAppIsRunning, initialData?.id,nodes.length]); }, [appRuntimeData, currentAppKey, currentAppIsRunning, initialData?.id, initialData?.components, nodes.length]);
const updateCanvasDataMapDebounced = useRef( const updateCanvasDataMapDebounced = useRef(
debounce((dispatch: Dispatch<any>, canvasDataMap: any, id: string, nodes: Node[], edges: Edge[]) => { debounce((dispatch: Dispatch<any>, canvasDataMap: any, id: string, nodes: Node[], edges: Edge[]) => {

@ -147,6 +147,16 @@ export const convertFlowData = (flowData: any, useDefault = true) => {
node.data.compId = nodeConfig.component.compId; node.data.compId = nodeConfig.component.compId;
} }
// 保留节点状态信息(用于历史实例查看)
if (nodeConfig.status) {
node.data.status = nodeConfig.status;
console.log(`convertFlowData - 保留节点 ${nodeId} 的状态:`, nodeConfig.status);
}
if (nodeConfig.isStatusVisible !== undefined) {
node.data.isStatusVisible = nodeConfig.isStatusVisible;
console.log(`convertFlowData - 保留节点 ${nodeId} 的状态可见性:`, nodeConfig.isStatusVisible);
}
// 注册循环节点类型 // 注册循环节点类型
if (nodeType === 'LOOP') { if (nodeType === 'LOOP') {
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
@ -379,6 +389,8 @@ export const convertFlowData = (flowData: any, useDefault = true) => {
}); });
} }
} }
console.log('nodes, edges:', nodes, edges);
return { nodes, edges }; return { nodes, edges };
}; };
@ -675,12 +687,15 @@ const getNodeApiIns = (nodeId: string, nodeConfig: any, currentProjectCompData:
else if (nodeId.includes('end')) { else if (nodeId.includes('end')) {
return [{ name: 'end', desc: '', dataType: '', defaultValue: '' }]; return [{ name: 'end', desc: '', dataType: '', defaultValue: '' }];
} }
else if (nodeConfig.component?.type === 'SUB') {
return [{ name: 'start', desc: '', dataType: '', defaultValue: '' }];
}
else { else {
const comp = currentProjectCompData.filter(item => { const comp = currentProjectCompData.filter(item => {
return (item.id || item?.comp?.id) === nodeConfig?.component?.compId; return (item.id || item?.comp?.id) === nodeConfig?.component?.compId;
}); });
if (comp && comp.length > 0) { if (comp && comp.length > 0) {
const apiIns = comp[0].def?.apis || comp[0]?.comp.def?.apis; const apiIns = comp[0]?.def?.apis || comp[0]?.comp?.def?.apis || [];
return apiIns.map(v => { return apiIns.map(v => {
return { return {
...v, ...v,
@ -768,6 +783,9 @@ const getNodeApiOuts = (nodeId: string, nodeConfig: any, currentProjectCompData:
else if (nodeId.includes('end')) { else if (nodeId.includes('end')) {
return []; return [];
} }
else if (nodeConfig.component?.type === 'SUB') {
return [{ name: 'done', desc: '', dataType: '', defaultValue: '' }];
}
else { else {
const comp = currentProjectCompData.filter(item => item.id === nodeConfig?.component?.compId); const comp = currentProjectCompData.filter(item => item.id === nodeConfig?.component?.compId);
if (comp && comp.length > 0) { if (comp && comp.length > 0) {

Loading…
Cancel
Save