import { useState, useRef, useEffect } from 'react'; import { History, Trash2, Check, X, RefreshCw, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import type { AIWritingSessionSummary } from '../../api/ai-writing-sessions'; export const STATUS_LABELS: Record = { in_progress: { label: '进行中', color: 'text-blue-500' }, // 后台挂起中:后端正自动驱动到定稿(离页/刷新/切号不打断)。 background: { label: '挂起中', color: 'text-sky-500' }, draft_ready: { label: '草稿', color: 'text-amber-500' }, review_ready: { label: '审核', color: 'text-purple-500' }, done: { label: '完成', color: 'text-green-500' }, error: { label: '错误', color: 'text-destructive' }, }; export function formatRelative(isoStr: string): string { const ms = Date.now() - new Date(isoStr).getTime(); const mins = Math.floor(ms / 60000); if (mins < 1) return '刚刚'; if (mins < 60) return `${mins} 分钟前`; const hrs = Math.floor(mins / 60); if (hrs < 24) return `${hrs} 小时前`; const days = Math.floor(hrs / 24); if (days < 7) return `${days} 天前`; return new Date(isoStr).toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' }); } export interface SessionItemProps { session: AIWritingSessionSummary; isSelected: boolean; onSelect: () => void; /** 「挂起中」记录点击时改为查看进度(流程图弹窗),不直接打开会话。 */ onShowProgress?: () => void; onDelete: () => void; onRename: (title: string) => void; } export function SessionItem({ session, isSelected, onSelect, onShowProgress, onDelete, onRename }: SessionItemProps) { const isBackground = session.status === 'background'; const handleRowClick = isBackground && onShowProgress ? onShowProgress : onSelect; const [editing, setEditing] = useState(false); const [editValue, setEditValue] = useState(session.title); const inputRef = useRef(null); const { label, color } = STATUS_LABELS[session.status] ?? { label: session.status, color: 'text-muted-foreground' }; useEffect(() => { if (editing) inputRef.current?.focus(); }, [editing]); function commitRename() { const trimmed = editValue.trim(); if (trimmed && trimmed !== session.title) onRename(trimmed); setEditing(false); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === 'Enter') commitRename(); else if (e.key === 'Escape') { setEditValue(session.title); setEditing(false); } } return (
{editing ? (
e.stopPropagation()}> setEditValue(e.target.value)} onKeyDown={handleKeyDown} />
) : (

{ e.stopPropagation(); setEditing(true); }} title="双击重命名" > {session.title}

)}
{session.status === 'background' && } {label} · {formatRelative(session.updated_at)}
{/* 删除按钮,hover 时显示 */} {!editing && ( )}
); } interface AIWritingHistoryDropdownProps { sessions: AIWritingSessionSummary[]; selectedId: string | null; loading: boolean; onSelect: (session: AIWritingSessionSummary) => void; /** 点击「挂起中」记录时查看进度(流程图弹窗),不直接打开会话。 */ onShowProgress?: (session: AIWritingSessionSummary) => void; onDelete: (id: string) => void; onRename: (id: string, title: string) => void; onRefresh: () => void; } export function AIWritingHistoryDropdown({ sessions, selectedId, loading, onSelect, onShowProgress, onDelete, onRename, onRefresh, }: AIWritingHistoryDropdownProps) { const [open, setOpen] = useState(false); const containerRef = useRef(null); useEffect(() => { if (!open) return; function handleClickOutside(e: MouseEvent) { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setOpen(false); } } document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [open]); function handleOpen() { setOpen((v) => { if (!v) onRefresh(); return !v; }); } return (
{open && (
{/* 头部 */}
写作历史
{/* 列表 */}
{sessions.length === 0 ? (
{loading ? '加载中…' : '暂无历史记录'}
) : ( sessions.map((s) => ( { onSelect(s); setOpen(false); }} onShowProgress={onShowProgress ? () => { onShowProgress(s); setOpen(false); } : undefined} onDelete={() => onDelete(s.id)} onRename={(title) => onRename(s.id, title)} /> )) )}
)}
); }