修复音乐分页问题

This commit is contained in:
mtvpls
2026-05-19 16:15:46 +08:00
rodzic 2cabf76c2d
commit b949b6da91
+98 -4
Wyświetl plik
@@ -201,6 +201,10 @@ export default function MusicPage() {
const [currentView, setCurrentView] = useState<'playlists' | 'songs' | 'myPlaylists'>('playlists');
const [currentPlaylistTitle, setCurrentPlaylistTitle] = useState('');
const [searchKeyword, setSearchKeyword] = useState('');
const [activeSearchKeyword, setActiveSearchKeyword] = useState('');
const [searchPage, setSearchPage] = useState(1);
const [searchHasMore, setSearchHasMore] = useState(false);
const [loadingMoreSearch, setLoadingMoreSearch] = useState(false);
const [currentSong, setCurrentSong] = useState<Song | null>(null);
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
@@ -277,6 +281,7 @@ export default function MusicPage() {
const audioRef = useRef<HTMLAudioElement>(null);
const lyricsContainerRef = useRef<HTMLDivElement>(null);
const searchLoadMoreRef = useRef<HTMLDivElement>(null);
const lastSaveTimeRef = useRef<number>(0);
const restoredTimeRef = useRef<number>(0);
const songStartTimeRef = useRef<number>(0); // 歌曲开始播放的时间戳
@@ -702,6 +707,9 @@ export default function MusicPage() {
const data = await response.json();
setSongs((data.data?.list || []).map(mapSong));
setCurrentPlaylistTitle(playlistName);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
setCurrentView('songs');
} catch (error) {
console.error('加载歌单失败:', error);
@@ -785,25 +793,68 @@ export default function MusicPage() {
// 搜索歌曲
const searchSongs = async () => {
if (!searchKeyword.trim()) return;
const keyword = searchKeyword.trim();
if (!keyword) return;
setLoading(true);
try {
const response = await fetch(
`/api/music/v2/search?source=${currentSource}&q=${encodeURIComponent(searchKeyword)}&page=1&limit=20`
`/api/music/v2/search?source=${currentSource}&q=${encodeURIComponent(keyword)}&page=1&limit=20`
);
const data = await response.json();
setSongs((data.data?.list || []).map(mapSong));
setCurrentPlaylistTitle(`搜索: ${searchKeyword}`);
setActiveSearchKeyword(keyword);
setSearchPage(1);
setSearchHasMore(Boolean(data.data?.hasMore));
setCurrentPlaylistTitle(`搜索: ${keyword}`);
setCurrentView('songs');
} catch (error) {
console.error('搜索失败:', error);
setSongs([]);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
} finally {
setLoading(false);
}
};
const loadMoreSearchSongs = async () => {
const keyword = activeSearchKeyword.trim();
if (!keyword || loadingMoreSearch || !searchHasMore) return;
const nextPage = searchPage + 1;
setLoadingMoreSearch(true);
try {
const response = await fetch(
`/api/music/v2/search?source=${currentSource}&q=${encodeURIComponent(keyword)}&page=${nextPage}&limit=20`
);
const data = await response.json();
if (response.ok && data.success) {
const nextSongs = (data.data?.list || []).map(mapSong);
setSongs((prev) => [...prev, ...nextSongs]);
setSearchPage(nextPage);
setSearchHasMore(Boolean(data.data?.hasMore));
} else {
setToast({
message: data.error?.message || '加载更多失败',
type: 'error',
onClose: () => setToast(null),
});
}
} catch (error) {
console.error('加载更多搜索结果失败:', error);
setToast({
message: '加载更多失败',
type: 'error',
onClose: () => setToast(null),
});
} finally {
setLoadingMoreSearch(false);
}
};
// 打开添加到歌单弹窗
const handleAddToPlaylist = (song: Song, e: React.MouseEvent) => {
e.stopPropagation(); // 阻止事件冒泡,避免触发播放
@@ -1416,6 +1467,9 @@ export default function MusicPage() {
if (currentView === 'songs') {
setCurrentView('playlists');
setSongs([]);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
} else if (currentView === 'myPlaylists') {
setCurrentView('playlists');
setSelectedUserPlaylist(null);
@@ -1444,6 +1498,9 @@ export default function MusicPage() {
setCurrentView('playlists');
setSongs([]);
setSearchKeyword('');
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
};
// 音频事件监听
@@ -1602,6 +1659,27 @@ export default function MusicPage() {
}
};
useEffect(() => {
const sentinel = searchLoadMoreRef.current;
if (!sentinel || !activeSearchKeyword || !searchHasMore) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0]?.isIntersecting) {
loadMoreSearchSongs();
}
},
{
root: null,
rootMargin: '240px 0px 240px 0px',
threshold: 0,
}
);
observer.observe(sentinel);
return () => observer.disconnect();
}, [activeSearchKeyword, searchHasMore, loadingMoreSearch, searchPage]);
// 进度条拖动
const handleProgressChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTime = (parseFloat(e.target.value) / 100) * duration;
@@ -2122,9 +2200,25 @@ export default function MusicPage() {
</div>
))}
</div>
{activeSearchKeyword && (
<div ref={searchLoadMoreRef} className="mt-6 flex min-h-10 justify-center">
{searchHasMore ? (
loadingMoreSearch ? (
<div className="rounded-lg border border-white/10 bg-white/5 px-5 py-2.5">
<MusicLoadingIndicator size="sm" className="gap-2 text-white" />
</div>
) : (
<div className="text-xs text-zinc-500">
</div>
)
) : songs.length > 0 ? (
<div className="text-xs text-zinc-500"></div>
) : null}
</div>
)}
</div>
)}
{/* My Playlists View */}
{currentView === 'myPlaylists' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">