feat(music-list): 添加音乐到用户歌单功能

- 新增"添加到我的歌单"选项,仅在用户登录时显示- 实现用户歌单获取和音乐添加到歌单的功能
- 添加相关API调用和错误处理
- 优化分页配置,使用本地状态管理
This commit is contained in:
ikmkj
2025-07-27 15:23:20 +08:00
parent 4bbaff62d0
commit 8dc53982e8

View File

@@ -100,7 +100,8 @@
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="addToPlaylist">添加到播放列表</el-dropdown-item> <el-dropdown-item command="addToPlaylist">添加到播放列表</el-dropdown-item>
<el-dropdown-item command="playNext">下一首播放</el-dropdown-item> <el-dropdown-item command="playNext">下一首播放</el-dropdown-item>
<el-dropdown-item command="downloadMusic">下载音乐</el-dropdown-item> <el-dropdown-item v-if="userStore.isLoggedIn" command="showAddToPlaylistDialog" divided>添加到我的歌单</el-dropdown-item>
<el-dropdown-item command="downloadMusic" :divided="!userStore.isLoggedIn">下载音乐</el-dropdown-item>
<el-dropdown-item command="downloadLyric">下载歌词</el-dropdown-item> <el-dropdown-item command="downloadLyric">下载歌词</el-dropdown-item>
<el-dropdown-item v-if="detailInMore" command="goToMusicDetail">音乐详情</el-dropdown-item> <el-dropdown-item v-if="detailInMore" command="goToMusicDetail">音乐详情</el-dropdown-item>
<el-dropdown-item command="share" v-if="false">分享</el-dropdown-item> <el-dropdown-item command="share" v-if="false">分享</el-dropdown-item>
@@ -115,13 +116,30 @@
<el-pagination <el-pagination
v-model:current-page="localCurrentPage" v-model:current-page="localCurrentPage"
v-model:page-size="localPageSize" v-model:page-size="localPageSize"
:page-sizes="[10, 20, 50, 100]" :page-sizes="pageSizes"
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
:total="total" :total="total"
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
/> />
</div> </div>
<!-- 添加到歌单弹窗 -->
<el-dialog v-model="isAddToPlaylistDialogVisible" title="添加到歌单" width="300px">
<div v-loading="loadingUserPlaylists" class="dialog-playlist-container">
<ul v-if="userPlaylists.length > 0" class="dialog-playlist-list">
<li
v-for="playlist in userPlaylists"
:key="playlist.id"
class="dialog-playlist-item"
@click="handleAddToPlaylist(currentMusicToAdd, playlist.id)"
>
{{ playlist.name }}
</li>
</ul>
<el-empty v-else-if="!loadingUserPlaylists" description="您还没有创建过歌单" />
</div>
</el-dialog>
</div> </div>
</template> </template>
@@ -130,7 +148,9 @@ import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { VideoPlay, VideoPause, Star, More, InfoFilled, Pointer } from '@element-plus/icons-vue' import { VideoPlay, VideoPause, Star, More, InfoFilled, Pointer } from '@element-plus/icons-vue'
import { usePlayerStore } from '../stores/player' import { usePlayerStore } from '../stores/player'
import { useUserStore } from '../stores/user'
import { toggleCollectMusic, toggleLikeMusic } from '../api/music' import { toggleCollectMusic, toggleLikeMusic } from '../api/music'
import { getUserPlaylist, addMusicToPlaylist } from '../api/playlist'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
const props = defineProps({ const props = defineProps({
@@ -171,6 +191,7 @@ const router = useRouter()
// 使用本地状态来代替直接绑定到props // 使用本地状态来代替直接绑定到props
const localCurrentPage = ref(props.currentPage) const localCurrentPage = ref(props.currentPage)
const localPageSize = ref(props.pageSize) const localPageSize = ref(props.pageSize)
const pageSizes = [10, 20, 50, 100] // 添加分页大小选项
// 监听props变化更新本地状态 // 监听props变化更新本地状态
watch(() => props.currentPage, (newVal) => { watch(() => props.currentPage, (newVal) => {
@@ -182,6 +203,52 @@ watch(() => props.pageSize, (newVal) => {
}) })
const playerStore = usePlayerStore() const playerStore = usePlayerStore()
const userStore = useUserStore()
const userPlaylists = ref([])
const loadingUserPlaylists = ref(false)
const isAddToPlaylistDialogVisible = ref(false)
const currentMusicToAdd = ref(null)
// 获取用户创建的歌单
const fetchUserPlaylists = async () => {
if (!userStore.isLoggedIn) {
userPlaylists.value = []
return
}
loadingUserPlaylists.value = true
try {
// 获取用户所有歌单这里设置一个比较大的size
const res = await getUserPlaylist(1, 200)
if (res.code === 200) {
userPlaylists.value = res.data.records || res.data.list || []
} else {
ElMessage.error(res.message || '获取您的歌单失败')
}
} catch (error) {
console.error('获取用户歌单失败:', error)
ElMessage.error('获取您的歌单失败')
} finally {
loadingUserPlaylists.value = false
}
}
// 将音乐添加到歌单
const handleAddToPlaylist = async (music, playlistId) => {
if (!music || !playlistId) return
try {
const res = await addMusicToPlaylist(playlistId, music.id)
if (res.code === 200 && res.data) {
ElMessage.success(`已将《${music.name}》添加到歌单`)
isAddToPlaylistDialogVisible.value = false
} else {
ElMessage.error(res.message || '添加失败')
}
} catch (error) {
console.error('添加到歌单失败:', error)
ElMessage.error('添加失败,请稍后重试')
}
}
// 跳转到音乐详情页 // 跳转到音乐详情页
const goToMusicDetail = (id) => { const goToMusicDetail = (id) => {
@@ -262,6 +329,11 @@ const handleCommand = (command, music) => {
ElMessage.success('已添加到播放列表') ElMessage.success('已添加到播放列表')
} }
break break
case 'showAddToPlaylistDialog':
currentMusicToAdd.value = music
fetchUserPlaylists()
isAddToPlaylistDialogVisible.value = true
break
case 'share': case 'share':
ElMessage.info('分享功能开发中') ElMessage.info('分享功能开发中')
break break
@@ -318,6 +390,29 @@ const handleCurrentChange = (page) => {
</script> </script>
<style scoped> <style scoped>
.dialog-playlist-container {
min-height: 150px;
max-height: 300px;
overflow-y: auto;
}
.dialog-playlist-list {
list-style: none;
padding: 0;
margin: 0;
}
.dialog-playlist-item {
padding: 10px 15px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.2s;
}
.dialog-playlist-item:hover {
background-color: #f5f7fa;
}
.music-list { .music-list {
width: 100%; width: 100%;
border-radius: 8px; border-radius: 8px;