HF_catalyst / frontend /components /HistoryPanel.tsx
SissiFeng's picture
Initial commit
cdb8847
import React, { useState, useEffect } from 'react';
import { Workflow, HistoryItem } from '../types/types';
interface HistoryPanelProps {
onSelectWorkflow: (workflow: Workflow) => void;
currentWorkflow: Workflow | null;
}
// 本地存储键
const HISTORY_STORAGE_KEY = 'workflow_history';
// 最大历史记录数
const MAX_HISTORY_ITEMS = 10;
const HistoryPanel: React.FC<HistoryPanelProps> = ({
onSelectWorkflow,
currentWorkflow,
}) => {
const [historyItems, setHistoryItems] = useState<HistoryItem[]>([]);
const [expanded, setExpanded] = useState<boolean>(true);
// 加载历史记录
useEffect(() => {
const loadHistory = () => {
try {
const savedHistory = localStorage.getItem(HISTORY_STORAGE_KEY);
if (savedHistory) {
const parsedHistory = JSON.parse(savedHistory) as HistoryItem[];
setHistoryItems(parsedHistory);
}
} catch (error) {
console.error('加载历史记录失败:', error);
}
};
loadHistory();
}, []);
// 保存工作流到历史记录
const saveToHistory = (workflow: Workflow, result?: any) => {
try {
// 创建新的历史项
const newItem: HistoryItem = {
id: `hist_${Date.now()}`,
workflow,
result,
timestamp: new Date().toISOString(),
};
// 更新state
const updatedHistory = [newItem, ...historyItems]
.slice(0, MAX_HISTORY_ITEMS);
setHistoryItems(updatedHistory);
// 保存到localStorage
localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(updatedHistory));
} catch (error) {
console.error('保存历史记录失败:', error);
}
};
// 清空历史记录
const clearHistory = () => {
setHistoryItems([]);
localStorage.removeItem(HISTORY_STORAGE_KEY);
};
// 选择历史项
const handleSelectHistoryItem = (item: HistoryItem) => {
onSelectWorkflow(item.workflow);
};
// 删除单个历史项
const handleDeleteHistoryItem = (itemId: string, e: React.MouseEvent) => {
e.stopPropagation(); // 防止点击传播到父元素
const updatedHistory = historyItems.filter(item => item.id !== itemId);
setHistoryItems(updatedHistory);
localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(updatedHistory));
};
// 格式化时间戳
const formatTimestamp = (timestamp: string) => {
try {
const date = new Date(timestamp);
// 如果是今天,只显示时间
const now = new Date();
const isToday =
date.getDate() === now.getDate() &&
date.getMonth() === now.getMonth() &&
date.getFullYear() === now.getFullYear();
if (isToday) {
return date.toLocaleTimeString();
}
// 否则显示日期和时间
return date.toLocaleString();
} catch (error) {
return timestamp;
}
};
// 切换展开/折叠
const toggleExpanded = () => {
setExpanded(!expanded);
};
return (
<div className="history-panel">
<div className="history-header" onClick={toggleExpanded}>
<h3>历史记录</h3>
<span className={`expand-icon ${expanded ? 'expanded' : ''}`}>
{expanded ? '▼' : '▶'}
</span>
</div>
{expanded && (
<>
{historyItems.length > 0 ? (
<div className="history-list">
{historyItems.map((item) => (
<div
key={item.id}
className={`history-item ${currentWorkflow?.name === item.workflow.name ? 'active' : ''}`}
onClick={() => handleSelectHistoryItem(item)}
>
<div className="history-item-content">
<div className="history-item-name">
{item.workflow.name || '未命名工作流'}
</div>
<div className="history-item-timestamp">
{formatTimestamp(item.timestamp)}
</div>
</div>
<div className="history-item-stats">
<span>{item.workflow.nodes.length} 节点</span>
<span>{item.workflow.edges.length} 边</span>
</div>
<div className="history-item-actions">
<button
className="history-item-delete"
onClick={(e) => handleDeleteHistoryItem(item.id, e)}
title="删除"
>
</button>
</div>
</div>
))}
</div>
) : (
<div className="empty-history">
<p>没有历史记录</p>
<small>发送工作流后将在这里显示</small>
</div>
)}
{historyItems.length > 0 && (
<div className="history-actions">
<button
className="clear-history"
onClick={clearHistory}
>
清空历史记录
</button>
</div>
)}
</>
)}
<style jsx>{`
.history-panel {
background-color: #f8f9fa;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.history-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background-color: #f1f3f5;
cursor: pointer;
user-select: none;
}
.history-header h3 {
margin: 0;
font-size: 18px;
}
.expand-icon {
font-size: 12px;
transition: transform 0.2s;
}
.expand-icon.expanded {
transform: rotate(0deg);
}
.history-list {
max-height: 300px;
overflow-y: auto;
}
.history-item {
padding: 12px 15px;
border-bottom: 1px solid #e9ecef;
cursor: pointer;
transition: background-color 0.2s;
position: relative;
}
.history-item:hover {
background-color: #e9ecef;
}
.history-item.active {
background-color: rgba(0, 123, 255, 0.1);
border-left: 3px solid #007bff;
}
.history-item-content {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
}
.history-item-name {
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 200px;
}
.history-item-timestamp {
font-size: 12px;
color: #6c757d;
}
.history-item-stats {
display: flex;
gap: 10px;
font-size: 12px;
color: #6c757d;
}
.history-item-actions {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
opacity: 0;
transition: opacity 0.2s;
}
.history-item:hover .history-item-actions {
opacity: 1;
}
.history-item-delete {
width: 24px;
height: 24px;
border-radius: 50%;
background-color: #f8d7da;
color: #dc3545;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
transition: all 0.2s;
}
.history-item-delete:hover {
background-color: #dc3545;
color: white;
}
.empty-history {
padding: 20px;
text-align: center;
color: #6c757d;
}
.empty-history p {
margin: 0 0 5px;
}
.empty-history small {
font-size: 12px;
}
.history-actions {
padding: 10px 15px;
display: flex;
justify-content: center;
border-top: 1px solid #e9ecef;
}
.clear-history {
padding: 6px 12px;
background-color: #f8d7da;
color: #dc3545;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.clear-history:hover {
background-color: #dc3545;
color: white;
}
`}</style>
</div>
);
};
// 添加保存工作流方法到组件上
HistoryPanel.saveToHistory = (workflow: Workflow, result?: any) => {
try {
// 获取当前历史记录
const savedHistory = localStorage.getItem(HISTORY_STORAGE_KEY);
let history: HistoryItem[] = [];
if (savedHistory) {
history = JSON.parse(savedHistory);
}
// 创建新的历史项
const newItem: HistoryItem = {
id: `hist_${Date.now()}`,
workflow,
result,
timestamp: new Date().toISOString(),
};
// 更新历史记录
const updatedHistory = [newItem, ...history].slice(0, MAX_HISTORY_ITEMS);
// 保存到localStorage
localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(updatedHistory));
return true;
} catch (error) {
console.error('保存历史记录失败:', error);
return false;
}
};
export default HistoryPanel;