feat(music): 添加音乐点赞功能及前端交互

- 后端新增点赞接口 /music/{id}/like,支持用户登录后点赞/取消点赞音乐,记录点赞数据到 user_like_music 表
- 后端修改 MusicController.getMusicById 接口,支持传入用户ID以判断当前音乐是否被该用户点赞
- 后端 MusicDTO 新增 isLiked 字段,用于前端展示点赞状态
- 数据库新增 user_like_music 表,记录用户与音乐的点赞关系,包含唯一约束防止重复点赞
- 前端 MusicDetail.vue 页面新增点赞按钮及状态展示,支持点击切换点赞状态并实时更新 UI 与点赞数
- 前端新增 toggleLikeMusic API 调用及相应交互逻辑,成功后展示操作提示信息
- 评论表 comment 新增 target_type 字段注释及状态字段注释,播放历史与各关联表新增索引优化与外键约束微调
This commit is contained in:
ikmkj
2025-07-25 23:25:45 +08:00
parent 59b6b251db
commit 4435315acf
11 changed files with 431 additions and 248 deletions

View File

@@ -116,6 +116,15 @@ export function toggleCollectMusic(id) {
return api.post(`/music/${id}/collect`)
}
/**
* 点赞/取消点赞音乐
* @param {number} id 音乐ID
* @returns {Promise<any>}
*/
export function toggleLikeMusic(id) {
return api.post(`/music/${id}/like`)
}
/**
* 获取收藏的音乐列表
* @param {number} page 页码

View File

@@ -73,6 +73,14 @@
{{ music.collected ? '已收藏' : '收藏' }}
</el-button>
<el-button
:type="music.liked ? 'success' : 'default'"
@click="toggleLike"
>
<el-icon><component :is="music.liked ? 'Check' : 'Pointer'" /></el-icon>
{{ music.liked ? '已点赞' : '点赞' }} ({{ music.likeCount || 0 }})
</el-button>
<el-button
@click="addToPlaylist"
icon="Plus"
@@ -194,7 +202,7 @@ import { ref, computed, onMounted, watch, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { usePlayerStore } from '../stores/player'
import { useUserStore } from '../stores/user'
import { getMusicById, toggleCollectMusic, getHotMusic } from '../api/music'
import { getMusicById, toggleCollectMusic, getHotMusic, toggleLikeMusic } from '../api/music'
import { getCommentList, addComment, deleteComment as apiDeleteComment } from '../api/comment'
import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket'
import { ElMessage, ElMessageBox } from 'element-plus'
@@ -399,8 +407,9 @@ const toggleCollect = async () => {
try {
const res = await toggleCollectMusic(music.value.id)
if (res.code === 200) {
music.value.collected = !music.value.collected
ElMessage.success(music.value.collected ? '收藏成功' : '已取消收藏')
// 后端直接返回了最新的收藏状态 (true/false),直接赋值即可
music.value.collected = res.data
ElMessage.success(res.message || (music.value.collected ? '收藏成功' : '已取消收藏'))
} else {
ElMessage.error(res.message || '操作失败')
}
@@ -410,6 +419,29 @@ const toggleCollect = async () => {
}
}
// 切换点赞状态
const toggleLike = async () => {
try {
const res = await toggleLikeMusic(music.value.id);
if (res.code === 200) {
// 后端直接返回了最新的点赞状态 (true/false),直接赋值
music.value.liked = res.data;
// 更新点赞数
if (music.value.liked) {
music.value.likeCount = (music.value.likeCount || 0) + 1;
} else {
music.value.likeCount = Math.max(0, (music.value.likeCount || 0) - 1);
}
ElMessage.success(res.message || (music.value.liked ? '点赞成功' : '已取消点赞'));
} else {
ElMessage.error(res.message || '操作失败');
}
} catch (error) {
console.error('点赞操作失败:', error);
ElMessage.error('操作失败,请稍后重试');
}
};
// 添加到播放列表
const addToPlaylist = () => {
playerStore.addToPlaylist(music.value)