修复音乐分页问题

This commit is contained in:
mtvpls
2026-05-19 16:15:46 +08:00
parent 2cabf76c2d
commit b949b6da91
+98 -4
View File
@@ -201,6 +201,10 @@ export default function MusicPage() {
const [currentView, setCurrentView] = useState<'playlists' | 'songs' | 'myPlaylists'>('playlists'); const [currentView, setCurrentView] = useState<'playlists' | 'songs' | 'myPlaylists'>('playlists');
const [currentPlaylistTitle, setCurrentPlaylistTitle] = useState(''); const [currentPlaylistTitle, setCurrentPlaylistTitle] = useState('');
const [searchKeyword, setSearchKeyword] = 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 [currentSong, setCurrentSong] = useState<Song | null>(null);
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0); const [currentTime, setCurrentTime] = useState(0);
@@ -277,6 +281,7 @@ export default function MusicPage() {
const audioRef = useRef<HTMLAudioElement>(null); const audioRef = useRef<HTMLAudioElement>(null);
const lyricsContainerRef = useRef<HTMLDivElement>(null); const lyricsContainerRef = useRef<HTMLDivElement>(null);
const searchLoadMoreRef = useRef<HTMLDivElement>(null);
const lastSaveTimeRef = useRef<number>(0); const lastSaveTimeRef = useRef<number>(0);
const restoredTimeRef = useRef<number>(0); const restoredTimeRef = useRef<number>(0);
const songStartTimeRef = useRef<number>(0); // 歌曲开始播放的时间戳 const songStartTimeRef = useRef<number>(0); // 歌曲开始播放的时间戳
@@ -702,6 +707,9 @@ export default function MusicPage() {
const data = await response.json(); const data = await response.json();
setSongs((data.data?.list || []).map(mapSong)); setSongs((data.data?.list || []).map(mapSong));
setCurrentPlaylistTitle(playlistName); setCurrentPlaylistTitle(playlistName);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
setCurrentView('songs'); setCurrentView('songs');
} catch (error) { } catch (error) {
console.error('加载歌单失败:', error); console.error('加载歌单失败:', error);
@@ -785,25 +793,68 @@ export default function MusicPage() {
// 搜索歌曲 // 搜索歌曲
const searchSongs = async () => { const searchSongs = async () => {
if (!searchKeyword.trim()) return; const keyword = searchKeyword.trim();
if (!keyword) return;
setLoading(true); setLoading(true);
try { try {
const response = await fetch( 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(); const data = await response.json();
setSongs((data.data?.list || []).map(mapSong)); setSongs((data.data?.list || []).map(mapSong));
setCurrentPlaylistTitle(`搜索: ${searchKeyword}`); setActiveSearchKeyword(keyword);
setSearchPage(1);
setSearchHasMore(Boolean(data.data?.hasMore));
setCurrentPlaylistTitle(`搜索: ${keyword}`);
setCurrentView('songs'); setCurrentView('songs');
} catch (error) { } catch (error) {
console.error('搜索失败:', error); console.error('搜索失败:', error);
setSongs([]); setSongs([]);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
} finally { } finally {
setLoading(false); 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) => { const handleAddToPlaylist = (song: Song, e: React.MouseEvent) => {
e.stopPropagation(); // 阻止事件冒泡,避免触发播放 e.stopPropagation(); // 阻止事件冒泡,避免触发播放
@@ -1416,6 +1467,9 @@ export default function MusicPage() {
if (currentView === 'songs') { if (currentView === 'songs') {
setCurrentView('playlists'); setCurrentView('playlists');
setSongs([]); setSongs([]);
setActiveSearchKeyword('');
setSearchPage(1);
setSearchHasMore(false);
} else if (currentView === 'myPlaylists') { } else if (currentView === 'myPlaylists') {
setCurrentView('playlists'); setCurrentView('playlists');
setSelectedUserPlaylist(null); setSelectedUserPlaylist(null);
@@ -1444,6 +1498,9 @@ export default function MusicPage() {
setCurrentView('playlists'); setCurrentView('playlists');
setSongs([]); setSongs([]);
setSearchKeyword(''); 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 handleProgressChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTime = (parseFloat(e.target.value) / 100) * duration; const newTime = (parseFloat(e.target.value) / 100) * duration;
@@ -2122,9 +2200,25 @@ export default function MusicPage() {
</div> </div>
))} ))}
</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> </div>
)} )}
{/* My Playlists View */} {/* My Playlists View */}
{currentView === 'myPlaylists' && ( {currentView === 'myPlaylists' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-6">