// ============================================================ // SessionSidebar — 会话历史侧边栏 // 职责:展示会话列表、新建/切换/删除/重命名会话 // ============================================================ import { useState } from "react"; import { useI18n } from "../../lib/i18n"; import type { SessionSummary } from "../../types"; interface SessionSidebarProps { sessions: SessionSummary[]; activeSessionId: string | null; collapsed: boolean; onToggleCollapse: () => void; onNewSession: () => void; onSelectSession: (id: string) => void; onDeleteSession: (id: string) => void; onRenameSession: (id: string, title: string) => void; } /** 格式化相对时间 */ function formatRelativeTime(ts: number): string { const now = Date.now(); const diff = now - ts; const min = 60 * 1000; const hour = 60 * min; const day = 24 * hour; if (diff < min) return "刚刚"; if (diff < hour) return `${Math.floor(diff / min)}分钟前`; if (diff < day) return `${Math.floor(diff / hour)}小时前`; if (diff < 2 * day) return "昨天"; if (diff < 7 * day) return `${Math.floor(diff / day)}天前`; const d = new Date(ts); return `${d.getMonth() + 1}/${d.getDate()}`; } export function SessionSidebar({ sessions, activeSessionId, collapsed, onToggleCollapse, onNewSession, onSelectSession, onDeleteSession, onRenameSession, }: SessionSidebarProps) { const { t } = useI18n(); const [editingId, setEditingId] = useState(null); const [editTitle, setEditTitle] = useState(""); const handleStartRename = (id: string, currentTitle: string) => { setEditingId(id); setEditTitle(currentTitle); }; const handleConfirmRename = () => { if (editingId && editTitle.trim()) { onRenameSession(editingId, editTitle.trim()); } setEditingId(null); setEditTitle(""); }; const handleCancelRename = () => { setEditingId(null); setEditTitle(""); }; if (collapsed) { return (
); } return (
{sessions.length === 0 ? (
{t("sidebar.empty")}
) : ( sessions.map((session) => (
onSelectSession(session.id)} > {editingId === session.id ? (
e.stopPropagation()}> setEditTitle(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") handleConfirmRename(); if (e.key === "Escape") handleCancelRename(); }} autoFocus />
) : ( <>
{session.title}
{session.messageCount > 0 && ( {session.messageCount}{t("sidebar.messages")} )} {formatRelativeTime(session.lastActiveAt)}
)}
)) )}
); }