"use client"; import React from "react"; import { motion } from "framer-motion"; import { Box, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Divider, IconButton, Paper, Stack, TextField, Tooltip, Typography, alpha, } from "@mui/material"; import EditNoteRounded from "@mui/icons-material/EditNoteRounded"; import DeleteOutlineRounded from "@mui/icons-material/DeleteOutlineRounded"; import ChatBubbleOutlineRounded from "@mui/icons-material/ChatBubbleOutlineRounded"; import SearchRounded from "@mui/icons-material/SearchRounded"; import WarningRounded from "@mui/icons-material/WarningRounded"; import type { ChatSessionSummary } from "./GlobalChatbox.types"; type AgentHistoryPanelProps = { sessions: ChatSessionSummary[]; activeSessionId?: string; isHydrating?: boolean; onNewSession: () => void; onSelectSession: (sessionId: string) => void; onDeleteSession: (sessionId: string) => void; }; const formatRelativeDate = (timestamp: number) => { const date = new Date(timestamp); const now = new Date(); const isSameDay = date.toDateString() === now.toDateString(); if (isSameDay) { return date.toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit", }); } return date.toLocaleDateString("zh-CN", { month: "numeric", day: "numeric", }); }; const getDayStart = (date: Date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime(); const getSessionGroupLabel = (timestamp: number) => { const now = new Date(); const todayStart = getDayStart(now); const yesterdayStart = todayStart - 24 * 60 * 60 * 1000; const lastWeekStart = todayStart - 7 * 24 * 60 * 60 * 1000; if (timestamp >= todayStart) return "今天"; if (timestamp >= yesterdayStart) return "昨天"; if (timestamp >= lastWeekStart) return "过去 7 天"; return "更早"; }; export const AgentHistoryPanel = ({ sessions, activeSessionId, isHydrating = false, onNewSession, onSelectSession, onDeleteSession, }: AgentHistoryPanelProps) => { const [keyword, setKeyword] = React.useState(""); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = React.useState(false); const [pendingDeleteSessionId, setPendingDeleteSessionId] = React.useState(null); const filteredSessions = React.useMemo(() => { const normalizedKeyword = keyword.trim().toLowerCase(); if (!normalizedKeyword) return sessions; return sessions.filter((session) => session.title.toLowerCase().includes(normalizedKeyword)); }, [keyword, sessions]); const groupedSessions = React.useMemo(() => { const groups = new Map(); filteredSessions.forEach((session) => { const label = getSessionGroupLabel(session.updatedAt); const existing = groups.get(label); if (existing) { existing.push(session); } else { groups.set(label, [session]); } }); return Array.from(groups.entries()); }, [filteredSessions]); const pendingDeleteSession = filteredSessions.find( (session) => session.id === pendingDeleteSessionId, ); return ( <> 历史会话 本地保存于浏览器 setKeyword(event.target.value)} placeholder="搜索历史会话" size="small" fullWidth disabled={isHydrating} InputProps={{ startAdornment: , sx: { borderRadius: 3, bgcolor: alpha("#fff", 0.62), fontSize: "0.85rem", }, }} /> {sessions.length === 0 ? ( 暂无历史会话 新建对话后会自动出现在这里 ) : filteredSessions.length === 0 ? ( 未找到匹配会话 试试其他关键词 ) : ( {groupedSessions.map(([groupLabel, groupSessions]) => ( {groupLabel} {groupSessions.map((session) => { const isActive = session.id === activeSessionId; return ( onSelectSession(session.id)} sx={{ px: 1.25, py: 1, borderRadius: 3, cursor: isHydrating ? "default" : "pointer", bgcolor: isActive ? alpha("#00acc1", 0.12) : alpha("#fff", 0.56), border: `1px solid ${isActive ? alpha("#00acc1", 0.25) : alpha("#fff", 0.72)}`, boxShadow: isActive ? `0 8px 20px ${alpha("#00acc1", 0.12)}` : `0 4px 12px ${alpha("#000", 0.03)}`, transition: "all 0.2s ease", pointerEvents: isHydrating ? "none" : "auto", "&:hover": { bgcolor: isActive ? alpha("#00acc1", 0.14) : alpha("#fff", 0.86), borderColor: alpha("#00acc1", 0.2), }, }} > {session.title} {formatRelativeDate(session.updatedAt)} { event.stopPropagation(); setPendingDeleteSessionId(session.id); setIsDeleteDialogOpen(true); }} sx={{ width: 24, height: 24, color: "text.secondary", "&:hover": { color: "error.main", bgcolor: alpha("#ef5350", 0.08), }, }} > ); })} ))} )} setIsDeleteDialogOpen(false)} sx={{ zIndex: (theme) => theme.zIndex.modal + 200 }} TransitionProps={{ onExited: () => setPendingDeleteSessionId(null) }} PaperProps={{ sx: { borderRadius: 4, bgcolor: alpha("#fff", 0.85), backdropFilter: "blur(24px)", boxShadow: `0 16px 40px ${alpha("#000", 0.12)}`, border: `1px solid ${alpha("#fff", 0.6)}`, minWidth: 320, }, }} > 删除确认 确定要删除 {pendingDeleteSession ? ( “{pendingDeleteSession.title}” ) : ( "该会话" )} 吗?
此操作不可撤销,删除后聊天记录将永久丢失。
); };