mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-05-14 00:39:37 +08:00
fix: detail lack of title
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
@@ -17,6 +19,9 @@ function DetailPageClient() {
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [playRecord, setPlayRecord] = useState<PlayRecord | null>(null);
|
const [playRecord, setPlayRecord] = useState<PlayRecord | null>(null);
|
||||||
|
|
||||||
|
// 当接口缺失标题时,使用 URL 中的 title 参数作为后备
|
||||||
|
const fallbackTitle = searchParams.get('title') || '';
|
||||||
|
|
||||||
// 格式化剩余时间(如 1h 50m)
|
// 格式化剩余时间(如 1h 50m)
|
||||||
const formatDuration = (seconds: number) => {
|
const formatDuration = (seconds: number) => {
|
||||||
const h = Math.floor(seconds / 3600);
|
const h = Math.floor(seconds / 3600);
|
||||||
@@ -45,7 +50,15 @@ function DetailPageClient() {
|
|||||||
throw new Error('获取详情失败');
|
throw new Error('获取详情失败');
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setDetail(data);
|
// 如果接口中缺失标题,则补上备用标题
|
||||||
|
let finalData = data;
|
||||||
|
if (!data?.videoInfo?.title && fallbackTitle) {
|
||||||
|
finalData = {
|
||||||
|
...data,
|
||||||
|
videoInfo: { ...data.videoInfo, title: fallbackTitle },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
setDetail(finalData);
|
||||||
|
|
||||||
// 获取播放记录
|
// 获取播放记录
|
||||||
const allRecords = await getAllPlayRecords();
|
const allRecords = await getAllPlayRecords();
|
||||||
@@ -117,7 +130,7 @@ function DetailPageClient() {
|
|||||||
<div className='flex-shrink-0 w-full md:w-72'>
|
<div className='flex-shrink-0 w-full md:w-72'>
|
||||||
<Image
|
<Image
|
||||||
src={detail.videoInfo.cover || '/images/placeholder.png'}
|
src={detail.videoInfo.cover || '/images/placeholder.png'}
|
||||||
alt={detail.videoInfo.title}
|
alt={detail.videoInfo.title || fallbackTitle}
|
||||||
width={288}
|
width={288}
|
||||||
height={432}
|
height={432}
|
||||||
className='w-full rounded-xl object-cover'
|
className='w-full rounded-xl object-cover'
|
||||||
@@ -131,7 +144,7 @@ function DetailPageClient() {
|
|||||||
style={{ height: '430px' }}
|
style={{ height: '430px' }}
|
||||||
>
|
>
|
||||||
<h1 className='text-3xl font-bold mb-2 tracking-wide flex items-center flex-shrink-0'>
|
<h1 className='text-3xl font-bold mb-2 tracking-wide flex items-center flex-shrink-0'>
|
||||||
{detail.videoInfo.title}
|
{detail.videoInfo.title || fallbackTitle}
|
||||||
</h1>
|
</h1>
|
||||||
<div className='flex flex-wrap items-center gap-3 text-base mb-4 opacity-80 flex-shrink-0'>
|
<div className='flex flex-wrap items-center gap-3 text-base mb-4 opacity-80 flex-shrink-0'>
|
||||||
{detail.videoInfo.remarks && (
|
{detail.videoInfo.remarks && (
|
||||||
@@ -157,7 +170,11 @@ function DetailPageClient() {
|
|||||||
<a
|
<a
|
||||||
href={`/play?source=${searchParams.get(
|
href={`/play?source=${searchParams.get(
|
||||||
'source'
|
'source'
|
||||||
)}&id=${searchParams.get('id')}`}
|
)}&id=${searchParams.get('id')}${
|
||||||
|
fallbackTitle
|
||||||
|
? `&title=${encodeURIComponent(fallbackTitle)}`
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
className='flex items-center justify-center gap-2 px-6 py-2 bg-green-500 hover:bg-green-600 rounded-lg transition-colors text-white'
|
className='flex items-center justify-center gap-2 px-6 py-2 bg-green-500 hover:bg-green-600 rounded-lg transition-colors text-white'
|
||||||
>
|
>
|
||||||
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
||||||
@@ -167,7 +184,11 @@ function DetailPageClient() {
|
|||||||
<a
|
<a
|
||||||
href={`/play?source=${searchParams.get(
|
href={`/play?source=${searchParams.get(
|
||||||
'source'
|
'source'
|
||||||
)}&id=${searchParams.get('id')}&index=1&position=0`}
|
)}&id=${searchParams.get('id')}&index=1&position=0${
|
||||||
|
fallbackTitle
|
||||||
|
? `&title=${encodeURIComponent(fallbackTitle)}`
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
className='flex items-center justify-center gap-2 px-6 py-2 bg-gray-500 hover:bg-gray-600 rounded-lg transition-colors text-white'
|
className='flex items-center justify-center gap-2 px-6 py-2 bg-gray-500 hover:bg-gray-600 rounded-lg transition-colors text-white'
|
||||||
>
|
>
|
||||||
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
||||||
@@ -180,7 +201,11 @@ function DetailPageClient() {
|
|||||||
<a
|
<a
|
||||||
href={`/play?source=${searchParams.get(
|
href={`/play?source=${searchParams.get(
|
||||||
'source'
|
'source'
|
||||||
)}&id=${searchParams.get('id')}&index=1&position=0`}
|
)}&id=${searchParams.get('id')}&index=1&position=0${
|
||||||
|
fallbackTitle
|
||||||
|
? `&title=${encodeURIComponent(fallbackTitle)}`
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
className='flex items-center justify-center gap-2 px-6 py-2 bg-green-500 hover:bg-green-600 rounded-lg transition-colors text-white'
|
className='flex items-center justify-center gap-2 px-6 py-2 bg-green-500 hover:bg-green-600 rounded-lg transition-colors text-white'
|
||||||
>
|
>
|
||||||
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
<div className='w-0 h-0 border-t-[6px] border-t-transparent border-l-[10px] border-l-white border-b-[6px] border-b-transparent'></div>
|
||||||
@@ -254,7 +279,11 @@ function DetailPageClient() {
|
|||||||
key={idx}
|
key={idx}
|
||||||
href={`/play?source=${searchParams.get(
|
href={`/play?source=${searchParams.get(
|
||||||
'source'
|
'source'
|
||||||
)}&id=${searchParams.get('id')}&index=${idx + 1}`}
|
)}&id=${searchParams.get('id')}&index=${idx + 1}${
|
||||||
|
fallbackTitle
|
||||||
|
? `&title=${encodeURIComponent(fallbackTitle)}`
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
className='bg-gray-500/80 hover:bg-green-500 text-white px-5 py-2 rounded-lg transition-colors text-base font-medium w-24 text-center'
|
className='bg-gray-500/80 hover:bg-green-500 text-white px-5 py-2 rounded-lg transition-colors text-base font-medium w-24 text-center'
|
||||||
>
|
>
|
||||||
第{idx + 1}集
|
第{idx + 1}集
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ function PlayPageClient() {
|
|||||||
// 使用 useState 保存视频详情
|
// 使用 useState 保存视频详情
|
||||||
const [detail, setDetail] = useState<VideoDetail | null>(null);
|
const [detail, setDetail] = useState<VideoDetail | null>(null);
|
||||||
|
|
||||||
// 轻量级界面状态,仅用于显示
|
// 初始标题:如果 URL 中携带 title 参数,则优先使用
|
||||||
const [videoTitle, setVideoTitle] = useState('');
|
const [videoTitle, setVideoTitle] = useState(searchParams.get('title') || '');
|
||||||
const [videoCover, setVideoCover] = useState('');
|
const [videoCover, setVideoCover] = useState('');
|
||||||
|
|
||||||
const [currentSource, setCurrentSource] = useState(
|
const [currentSource, setCurrentSource] = useState(
|
||||||
@@ -159,7 +159,7 @@ function PlayPageClient() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// 更新状态保存详情
|
// 更新状态保存详情
|
||||||
setVideoTitle(data.videoInfo.title);
|
setVideoTitle(data.videoInfo.title || videoTitle);
|
||||||
setVideoCover(data.videoInfo.cover);
|
setVideoCover(data.videoInfo.cover);
|
||||||
setDetail(data);
|
setDetail(data);
|
||||||
|
|
||||||
@@ -740,7 +740,11 @@ function PlayPageClient() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 处理换源
|
// 处理换源
|
||||||
const handleSourceChange = async (newSource: string, newId: string) => {
|
const handleSourceChange = async (
|
||||||
|
newSource: string,
|
||||||
|
newId: string,
|
||||||
|
newTitle: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
// 显示换源加载状态
|
// 显示换源加载状态
|
||||||
setSourceChanging(true);
|
setSourceChanging(true);
|
||||||
@@ -782,7 +786,7 @@ function PlayPageClient() {
|
|||||||
// 关闭换源面板
|
// 关闭换源面板
|
||||||
setShowSourcePanel(false);
|
setShowSourcePanel(false);
|
||||||
|
|
||||||
setVideoTitle(newDetail.videoInfo.title);
|
setVideoTitle(newDetail.videoInfo.title || newTitle);
|
||||||
setVideoCover(newDetail.videoInfo.cover);
|
setVideoCover(newDetail.videoInfo.cover);
|
||||||
setCurrentSource(newSource);
|
setCurrentSource(newSource);
|
||||||
setCurrentId(newId);
|
setCurrentId(newId);
|
||||||
@@ -1293,7 +1297,11 @@ function PlayPageClient() {
|
|||||||
}`}
|
}`}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
!isCurrentSource &&
|
!isCurrentSource &&
|
||||||
handleSourceChange(result.source, result.id)
|
handleSourceChange(
|
||||||
|
result.source,
|
||||||
|
result.id,
|
||||||
|
result.title
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* 视频封面 */}
|
{/* 视频封面 */}
|
||||||
|
|||||||
@@ -110,7 +110,9 @@ export default function VideoCard({
|
|||||||
|
|
||||||
return deleted ? null : (
|
return deleted ? null : (
|
||||||
<Link
|
<Link
|
||||||
href={`/detail?source=${source}&id=${id}${from ? `&from=${from}` : ''}`}
|
href={`/detail?source=${source}&id=${id}&title=${encodeURIComponent(
|
||||||
|
title
|
||||||
|
)}${from ? `&from=${from}` : ''}`}
|
||||||
>
|
>
|
||||||
<div className='group relative w-full rounded-lg bg-transparent shadow-none flex flex-col'>
|
<div className='group relative w-full rounded-lg bg-transparent shadow-none flex flex-col'>
|
||||||
{/* 海报图片 - 2:3 比例 */}
|
{/* 海报图片 - 2:3 比例 */}
|
||||||
@@ -128,7 +130,11 @@ export default function VideoCard({
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
router.push(`/play?source=${source}&id=${id}`);
|
router.push(
|
||||||
|
`/play?source=${source}&id=${id}&title=${encodeURIComponent(
|
||||||
|
title
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
onMouseEnter={() => setPlayHover(true)}
|
onMouseEnter={() => setPlayHover(true)}
|
||||||
onMouseLeave={() => setPlayHover(false)}
|
onMouseLeave={() => setPlayHover(false)}
|
||||||
|
|||||||
Reference in New Issue
Block a user