feat(flowEditor): 添加历史版本应用功能功能

master
钟良源 2 weeks ago
parent a5ab8b1690
commit 72802cb143

@ -542,6 +542,8 @@ const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
<HandlerBar <HandlerBar
onPublish={handlePublish} onPublish={handlePublish}
isRunning={currentAppIsRunning} isRunning={currentAppIsRunning}
setNodes={setNodes}
setEdges={setEdges}
/> />
</Panel>} </Panel>}
<AlignmentGuides /> <AlignmentGuides />

@ -2,19 +2,29 @@ import React, { useState } from 'react';
import { Button } from '@arco-design/web-react'; import { Button } from '@arco-design/web-react';
import { IconSend, IconOrderedList } from '@arco-design/web-react/icon'; import { IconSend, IconOrderedList } from '@arco-design/web-react/icon';
import HistoryVersionModal from './historyVersionModal'; import HistoryVersionModal from './historyVersionModal';
import { Node, Edge } from '@xyflow/react';
interface HandlerBarProps { interface HandlerBarProps {
onPublish?: () => void; onPublish?: () => void;
isRunning?: boolean; isRunning?: boolean;
setNodes?: React.Dispatch<React.SetStateAction<Node[]>>;
setEdges?: React.Dispatch<React.SetStateAction<Edge[]>>;
} }
const HandlerBar: React.FC<HandlerBarProps> = ({ onPublish, isRunning }) => { const HandlerBar: React.FC<HandlerBarProps> = ({ onPublish, isRunning, setNodes, setEdges }) => {
const [historyModalVisible, setHistoryModalVisible] = useState(false); const [historyModalVisible, setHistoryModalVisible] = useState(false);
const handleHistoryClick = () => { const handleHistoryClick = () => {
setHistoryModalVisible(true); setHistoryModalVisible(true);
}; };
const handleApplyHistory = (nodes: Node[], edges: Edge[]) => {
if (setNodes && setEdges) {
setNodes(nodes);
setEdges(edges);
}
};
return ( return (
<> <>
<div className="handlex-bar" style={{ paddingRight: 50 }}> <div className="handlex-bar" style={{ paddingRight: 50 }}>
@ -44,6 +54,7 @@ const HandlerBar: React.FC<HandlerBarProps> = ({ onPublish, isRunning }) => {
<HistoryVersionModal <HistoryVersionModal
visible={historyModalVisible} visible={historyModalVisible}
onCancel={() => setHistoryModalVisible(false)} onCancel={() => setHistoryModalVisible(false)}
onApply={handleApplyHistory}
/> />
</> </>
); );

@ -1,16 +1,18 @@
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { Modal, List, Message, Spin, Pagination } from '@arco-design/web-react'; import { Modal, List, Message, Spin, Pagination, Button, Space } from '@arco-design/web-react';
import { ReactFlowProvider, ReactFlow, Background, Controls } from '@xyflow/react'; import { ReactFlowProvider, ReactFlow, Background, Controls } from '@xyflow/react';
import '@xyflow/react/dist/style.css'; import '@xyflow/react/dist/style.css';
import { historyPage } from '@/api/appRes'; import { historyPage } from '@/api/appRes';
import { convertFlowData } from '@/utils/convertFlowData'; import { convertFlowData } from '@/utils/convertFlowData';
import { nodeTypes } from '@/components/FlowEditor/node'; import { nodeTypes } from '@/components/FlowEditor/node';
import { useSelector } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { updateFlowData, updateCanvasDataMap } from '@/store/ideContainer';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
interface HistoryVersionModalProps { interface HistoryVersionModalProps {
visible: boolean; visible: boolean;
onCancel: () => void; onCancel: () => void;
onApply?: (nodes: any[], edges: any[]) => void;
} }
interface HistoryItem { interface HistoryItem {
@ -34,19 +36,19 @@ interface HistoryItem {
timestamp: number; timestamp: number;
} }
const HistoryVersionModal: React.FC<HistoryVersionModalProps> = ({ visible, onCancel }) => { const HistoryVersionModal: React.FC<HistoryVersionModalProps> = ({ visible, onCancel, onApply }) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [historyList, setHistoryList] = useState<HistoryItem[]>([]); const [historyList, setHistoryList] = useState<HistoryItem[]>([]);
const [selectedHistory, setSelectedHistory] = useState<HistoryItem | null>(null); const [selectedHistory, setSelectedHistory] = useState<HistoryItem | null>(null);
const [currPage, setCurrPage] = useState(1); const [currPage, setCurrPage] = useState(1);
const [totalCount, setTotalCount] = useState(0); const [totalCount, setTotalCount] = useState(0);
const { currentAppData } = useSelector(state => state.ideContainer); const { currentAppData } = useSelector(state => state.ideContainer);
const dispatch = useDispatch();
const pageSize = 10; const pageSize = 10;
// 获取历史版本列表 // 获取历史版本列表
const fetchHistoryList = async (page = 1) => { const fetchHistoryList = async (page = 1) => {
if (!currentAppData?.id) return; if (!currentAppData?.id) return;
console.log('currentAppData:', currentAppData);
setLoading(true); setLoading(true);
try { try {
const response: any = await historyPage({ const response: any = await historyPage({
@ -90,6 +92,53 @@ const HistoryVersionModal: React.FC<HistoryVersionModalProps> = ({ visible, onCa
return dayjs(Number(timestamp)).format('YYYY-MM-DD HH:mm:ss'); return dayjs(Number(timestamp)).format('YYYY-MM-DD HH:mm:ss');
}; };
// 应用历史版本到当前画布
const handleApplyVersion = () => {
if (!selectedHistory) {
Message.warning('请先选择一个历史版本');
return;
}
Modal.confirm({
title: '确认应用历史版本',
content: `确定要将 ${formatTimestamp(selectedHistory.timestamp)} 的版本应用到当前画布吗?当前未保存的修改将会丢失。`,
onOk: () => {
try {
// 转换历史版本数据为 ReactFlow 格式
const components = selectedHistory.res.main.components;
const convertedData = convertFlowData(components, false);
const { nodes, edges } = convertedData;
// 如果父组件提供了 onApply 回调,使用回调来更新画布
if (onApply) {
onApply(nodes, edges);
}
// 同时更新 Redux store 中的缓存数据
const canvasKey = currentAppData.key || currentAppData.id;
// 更新 flowData全局流程数据
dispatch(updateFlowData(convertedData));
// 更新 canvasDataMap画布缓存
dispatch(updateCanvasDataMap({
[canvasKey]: {
nodes,
edges,
timestamp: Date.now()
}
}));
Message.success('历史版本已应用到当前画布');
onCancel();
} catch (error) {
console.error('应用历史版本失败:', error);
Message.error('应用历史版本失败');
}
}
});
};
// 使用useMemo缓存转换后的画布数据避免在渲染时调用convertFlowData导致Redux dispatch // 使用useMemo缓存转换后的画布数据避免在渲染时调用convertFlowData导致Redux dispatch
const canvasData = useMemo(() => { const canvasData = useMemo(() => {
if (!selectedHistory) { if (!selectedHistory) {
@ -140,7 +189,18 @@ const HistoryVersionModal: React.FC<HistoryVersionModalProps> = ({ visible, onCa
title="历史版本" title="历史版本"
visible={visible} visible={visible}
onCancel={onCancel} onCancel={onCancel}
footer={null} footer={
<Space>
<Button onClick={onCancel}></Button>
<Button
type="primary"
onClick={handleApplyVersion}
disabled={!selectedHistory}
>
</Button>
</Space>
}
style={{ width: '90vw', maxWidth: 1400 }} style={{ width: '90vw', maxWidth: 1400 }}
> >
<Spin loading={loading} style={{ width: '100%', height: '100%' }}> <Spin loading={loading} style={{ width: '100%', height: '100%' }}>

Loading…
Cancel
Save