"use client"; import { useState } from "react"; import LoadingSpinner from "./LoadingSpinner"; import AudioPlayer from "./AudioPlayer"; interface Recording { id: string; title: string; duration: number; createdAt: string; audioUrl: string; } interface RecordingListProps { recordings: Recording[]; onRecordingUpdated?: (updatedRecording: Recording) => void; } export default function RecordingList({ recordings, onRecordingUpdated, }: RecordingListProps) { const [deletingId, setDeletingId] = useState(null); const [hoveredId, setHoveredId] = useState(null); const [renamingId, setRenamingId] = useState(null); const [renamingTitle, setRenamingTitle] = useState(""); const formatDuration = (seconds: number) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, "0")}`; }; const formatDate = (dateString: string) => { const date = new Date(dateString); const now = new Date(); const diffInHours = Math.floor( (now.getTime() - date.getTime()) / (1000 * 60 * 60) ); if (diffInHours < 24) { if (diffInHours < 1) { return "刚刚"; } else if (diffInHours < 2) { return "1小时前"; } else { return `${diffInHours}小时前`; } } else { return date.toLocaleDateString("zh-CN", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); } }; const handleDelete = async (id: string) => { if (!confirm("确定要删除这个录音吗?")) return; setDeletingId(id); try { const response = await fetch(`/api/recordings/${id}`, { method: "DELETE", }); if (response.ok) { // 触发父组件刷新 console.log("录音删除成功,触发刷新事件"); window.dispatchEvent(new CustomEvent("recording-deleted")); } else { throw new Error("删除失败"); } } catch (error) { console.error("删除错误:", error); alert("删除失败,请重试。"); } finally { setDeletingId(null); } }; const handleRename = async (id: string, newTitle: string) => { if (!newTitle.trim()) { alert("录音标题不能为空"); return; } console.log(`开始重命名录音: ${id}, 新标题: "${newTitle}"`); try { const response = await fetch(`/api/recordings/${id}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ title: newTitle.trim() }), }); if (response.ok) { const result = await response.json(); // 触发父组件刷新 console.log("录音重命名成功,触发刷新事件"); window.dispatchEvent(new CustomEvent("recording-renamed")); // 强制刷新当前录音的显示 const updatedRecording = result.data; // 调用父组件的更新回调 if (onRecordingUpdated && updatedRecording) { onRecordingUpdated(updatedRecording); } setRenamingId(null); setRenamingTitle(""); } else { const errorData = await response.json().catch(() => ({})); console.error( `重命名失败,状态码: ${response.status}, 错误信息:`, errorData ); throw new Error(`重命名失败: ${response.status}`); } } catch (error) { console.error("重命名错误:", error); alert("重命名失败,请重试。"); } }; const startRename = (recording: Recording) => { setRenamingId(recording.id); setRenamingTitle(recording.title); }; const cancelRename = () => { setRenamingId(null); setRenamingTitle(""); }; if (!recordings || recordings.length === 0) { return (

开始你的录音之旅

录制你的第一个音频,让创意在这里发声

); } return (
{recordings.map((recording) => (
setHoveredId(recording.id)} onMouseLeave={() => setHoveredId(null)} className="group relative bg-white dark:bg-gray-800/50 backdrop-blur-sm rounded-2xl border border-gray-100 dark:border-gray-700/50 p-6 hover:shadow-lg hover:shadow-blue-500/5 dark:hover:shadow-blue-400/5 transition-all duration-300 hover:scale-[1.02] hover:border-blue-200 dark:hover:border-blue-700/50" > {/* 背景装饰 */}
{/* 头部信息 */}
{renamingId === recording.id ? (
setRenamingTitle(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { handleRename(recording.id, renamingTitle); } else if (e.key === "Escape") { cancelRename(); } }} className="flex-1 px-3 py-1 border border-blue-300 dark:border-blue-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white text-lg font-semibold" maxLength={100} autoFocus />
) : (

{recording.title} {/* 当前标题: {recording.title} */}

)}
{formatDuration(recording.duration)}
{formatDate(recording.createdAt)}
{/* 操作按钮 */}
{/* 重命名按钮 */} {/* 删除按钮 */}
{/* 音频播放器 */}
{/* 播放器装饰 */}
))}
); }