Files
record-app-next/app/dashboard/page.tsx
2025-07-31 17:05:07 +08:00

160 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useEffect, useState, useCallback } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import Header from "@/components/Header";
import AudioRecorder from "@/components/AudioRecorder";
import RecordingList from "@/components/RecordingList";
import LoadingSpinner from "@/components/LoadingSpinner";
interface Recording {
id: string;
title: string;
duration: number;
createdAt: string;
audioUrl: string;
}
export default function DashboardPage() {
const { data: session, status } = useSession();
const router = useRouter();
const [recordings, setRecordings] = useState<Recording[]>([]);
const [isLoading, setIsLoading] = useState(true);
// 处理录音更新
const handleRecordingUpdated = useCallback((updatedRecording: Recording) => {
setRecordings((prevRecordings) =>
prevRecordings.map((recording) =>
recording.id === updatedRecording.id ? updatedRecording : recording
)
);
}, []);
// 获取录音列表
const fetchRecordings = useCallback(async () => {
try {
const response = await fetch("/api/recordings");
if (response.ok) {
const result = await response.json();
if (result.success && Array.isArray(result.data)) {
setRecordings(result.data);
} else {
console.error("API 返回数据格式错误:", result);
setRecordings([]);
}
} else {
console.error("获取录音列表失败:", response.status);
setRecordings([]);
}
} catch (error) {
console.error("获取录音列表失败:", error);
setRecordings([]);
} finally {
setIsLoading(false);
}
}, []);
// 监听录音上传和删除事件
useEffect(() => {
const handleRecordingUploaded = () => {
// 延迟一点时间确保服务器处理完成
setTimeout(() => {
fetchRecordings();
}, 500);
};
const handleRecordingDeleted = () => {
// 延迟一点时间确保服务器处理完成
setTimeout(() => {
fetchRecordings();
}, 500);
};
const handleRecordingRenamed = () => {
// 立即清除可能的缓存
// 延迟一点时间确保服务器处理完成
setTimeout(() => {
fetchRecordings();
}, 100); // 减少延迟时间
};
window.addEventListener("recording-uploaded", handleRecordingUploaded);
window.addEventListener("recording-deleted", handleRecordingDeleted);
window.addEventListener("recording-renamed", handleRecordingRenamed);
return () => {
window.removeEventListener("recording-uploaded", handleRecordingUploaded);
window.removeEventListener("recording-deleted", handleRecordingDeleted);
window.removeEventListener("recording-renamed", handleRecordingRenamed);
};
}, [fetchRecordings]);
// 初始加载录音列表
useEffect(() => {
if (status === "authenticated") {
fetchRecordings();
}
}, [status]);
// 检查认证状态
if (status === "loading") {
return (
<div className="flex justify-center items-center min-h-screen">
<LoadingSpinner size="lg" color="blue" text="加载中..." />
</div>
);
}
if (status === "unauthenticated") {
router.push("/login");
return null;
}
if (!session?.user) {
return null;
}
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
<Header />
<main className="container mx-auto p-4 md:p-8 max-w-6xl">
<div className="mb-12">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
, {session.user.name || session.user.email}!
</h2>
<p className="text-gray-600 dark:text-gray-400 text-lg">
</p>
</div>
<div className="mb-16">
<AudioRecorder />
</div>
<div>
<div className="flex justify-between items-center mb-6">
<h3 className="text-2xl md:text-3xl font-semibold text-gray-900 dark:text-white">
</h3>
<button
onClick={fetchRecordings}
className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
>
</button>
</div>
{isLoading ? (
<div className="text-center py-12">
<LoadingSpinner size="lg" color="blue" text="加载录音中..." />
</div>
) : (
<RecordingList recordings={recordings} />
)}
</div>
</main>
</div>
);
}