/* eslint-disable react-hooks/exhaustive-deps, no-console */ 'use client'; import { Heart } from 'lucide-react'; import Image from 'next/image'; import { useSearchParams } from 'next/navigation'; import { Suspense, useEffect, useState } from 'react'; import type { PlayRecord } from '@/lib/db.client'; import { generateStorageKey, getAllPlayRecords, isFavorited, toggleFavorite, } from '@/lib/db.client'; import { VideoDetail } from '@/lib/types'; import PageLayout from '@/components/PageLayout'; function DetailPageClient() { const searchParams = useSearchParams(); const [detail, setDetail] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [playRecord, setPlayRecord] = useState(null); const [favorited, setFavorited] = useState(false); // 当接口缺失标题时,使用 URL 中的 title 参数作为后备 const fallbackTitle = searchParams.get('title') || ''; // 格式化剩余时间(如 1h 50m) const formatDuration = (seconds: number) => { const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const parts: string[] = []; if (h) parts.push(`${h}h`); if (m) parts.push(`${m}m`); if (parts.length === 0) parts.push('0m'); return parts.join(' '); }; useEffect(() => { const source = searchParams.get('source'); const id = searchParams.get('id'); if (!source || !id) { setError('缺少必要参数'); setLoading(false); return; } const fetchData = async () => { try { const response = await fetch(`/api/detail?source=${source}&id=${id}`); if (!response.ok) { throw new Error('获取详情失败'); } const data = await response.json(); // 如果接口中缺失标题,则补上备用标题 let finalData = data; if (!data?.videoInfo?.title && fallbackTitle) { finalData = { ...data, videoInfo: { ...data.videoInfo, title: fallbackTitle }, }; } setDetail(finalData); // 获取播放记录 const allRecords = await getAllPlayRecords(); const key = generateStorageKey(source, id); setPlayRecord(allRecords[key] || null); // 检查收藏状态 try { const fav = await isFavorited(source, id); setFavorited(fav); } catch (checkErr) { console.error('检查收藏状态失败:', checkErr); } } catch (err) { setError(err instanceof Error ? err.message : '获取详情失败'); } finally { setLoading(false); } }; fetchData(); }, [searchParams]); // 切换收藏状态 const handleToggleFavorite = async () => { const source = searchParams.get('source'); const id = searchParams.get('id'); if (!source || !id || !detail) return; try { const newState = await toggleFavorite(source, id, { title: detail.videoInfo.title, source_name: detail.videoInfo.source_name, cover: detail.videoInfo.cover || '', total_episodes: detail.episodes?.length || 1, save_time: Date.now(), }); setFavorited(newState); } catch (err) { console.error('切换收藏失败:', err); } }; return (
{/* 顶部返回按钮已移入右侧信息容器 */} {loading ? (
) : error ? (
加载失败
{error}
) : !detail ? (
未找到视频详情
) : (
{/* 主信息区:左图右文 */}
{/* 返回按钮放置在主信息区左上角 */} {/* 封面 */}
{detail.videoInfo.title
{/* 右侧信息 */}

{detail.videoInfo.title || fallbackTitle}

{detail.videoInfo.remarks && ( {detail.videoInfo.remarks} )} {detail.videoInfo.year && ( {detail.videoInfo.year} )} {detail.videoInfo.source_name && ( {detail.videoInfo.source_name} )} {detail.videoInfo.type && ( {detail.videoInfo.type} )}
{/* 按钮区域 */}
{playRecord ? ( <> {/* 恢复播放 */}
恢复播放
{/* 从头开始 */}
从头开始
) : ( <> {/* 播放 */}
播放
)} {/* 爱心按钮 */}
{/* 播放记录进度条 */} {playRecord && (
{/* 进度条 */}
{/* 剩余时间 */} {playRecord.total_episodes > 1 ? `第${playRecord.index}集 剩余 ` : '剩余 '} {formatDuration( playRecord.total_time - playRecord.play_time )}
)} {detail.videoInfo.desc && (
{detail.videoInfo.desc}
)}
{/* 选集按钮区 */} {detail.episodes.length > 0 && (
选集
共 {detail.episodes.length} 集
{detail.episodes.map((episode, idx) => ( 第{idx + 1}集 ))}
)}
)}
); } export default function DetailPage() { return ( ); }