refactor(admin): 重构歌单管理功能提升代码质量

- 移除未使用的 computed 导入语句
- 添加错误处理工具 showErrorOnce 的导入
- 新增 playlistMusics 响应式变量存储歌单音乐数据
- 优化歌单详情加载逻辑,完善异常情况的数据重置
- 在音乐添加和移除操作后同步更新歌单列表数据
- 添加统一的错误处理机制替代原有 console.error
- 重构歌单权限校验逻辑,提取为独立的验证方法
- 增强管理员权限支持,允许后台管理员维护用户歌单
This commit is contained in:
ikmkj
2026-03-21 22:03:11 +08:00
parent f0fa9cf67d
commit f5d262f4fc
2 changed files with 683 additions and 665 deletions

View File

@@ -540,14 +540,7 @@ public class PlaylistServiceImpl implements PlaylistService {
// 获取歌单 // 获取歌单
Playlist playlist = playlistRepository.findById(id) Playlist playlist = playlistRepository.findById(id)
.orElseThrow(() -> new BusinessException("歌单不存在")); .orElseThrow(() -> new BusinessException("歌单不存在"));
validatePlaylistManagePermission(playlist, "无权修改该歌单");
// 获取当前登录用户
Long userId = StpUtil.getLoginIdAsLong();
// 检查是否是歌单创建者
if (!playlist.getCreator().getId().equals(userId)) {
throw new BusinessException("无权修改该歌单");
}
// 获取音乐 // 获取音乐
Music music = musicRepository.findById(musicId) Music music = musicRepository.findById(musicId)
@@ -571,14 +564,7 @@ public class PlaylistServiceImpl implements PlaylistService {
// 获取歌单 // 获取歌单
Playlist playlist = playlistRepository.findById(id) Playlist playlist = playlistRepository.findById(id)
.orElseThrow(() -> new BusinessException("歌单不存在")); .orElseThrow(() -> new BusinessException("歌单不存在"));
validatePlaylistManagePermission(playlist, "无权修改该歌单");
// 获取当前登录用户
Long userId = StpUtil.getLoginIdAsLong();
// 检查是否是歌单创建者
if (!playlist.getCreator().getId().equals(userId)) {
throw new BusinessException("无权修改该歌单");
}
// 获取音乐 // 获取音乐
Music music = musicRepository.findById(musicId) Music music = musicRepository.findById(musicId)
@@ -620,6 +606,21 @@ public class PlaylistServiceImpl implements PlaylistService {
.orElseThrow(() -> new BusinessException("歌单不存在")); .orElseThrow(() -> new BusinessException("歌单不存在"));
} }
/**
* 校验当前登录用户是否有权限管理歌单。
*
* 允许歌单创建者或管理员执行管理操作,避免后台管理员无法维护用户歌单。
*
* @param playlist 歌单实体
* @param errorMessage 无权限时的提示文案
*/
private void validatePlaylistManagePermission(Playlist playlist, String errorMessage) {
Long userId = StpUtil.getLoginIdAsLong();
if (!playlist.getCreator().getId().equals(userId) && !StpUtil.hasRole("admin")) {
throw new BusinessException(errorMessage);
}
}
/** /**
* 将实体转换为DTO * 将实体转换为DTO
* *

View File

@@ -1,9 +1,10 @@
<script setup> <script setup>
import { ref, onMounted, computed } from 'vue' import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getPlaylistList, getPlaylistById, addPlaylist as apiAddPlaylist, updatePlaylist as apiUpdatePlaylist, deletePlaylist as apiDeletePlaylist } from '../../api/playlist' import { getPlaylistList, getPlaylistById, addPlaylist as apiAddPlaylist, updatePlaylist as apiUpdatePlaylist, deletePlaylist as apiDeletePlaylist } from '../../api/playlist'
import { getPlaylistTypeList } from '../../api/playlistType' import { getPlaylistTypeList } from '../../api/playlistType'
import { processMusicUrl } from '../../api/music' import { processMusicUrl } from '../../api/music'
import { showErrorOnce } from '../../utils/errorHandler'
// 歌单列表 // 歌单列表
const playlistList = ref([]) const playlistList = ref([])
@@ -251,6 +252,7 @@ const musicDialogVisible = ref(false)
const currentPlaylistId = ref(null) const currentPlaylistId = ref(null)
const currentPlaylistName = ref('') const currentPlaylistName = ref('')
const musicList = ref([]) const musicList = ref([])
const playlistMusics = ref([])
const selectedMusicIds = ref([]) const selectedMusicIds = ref([])
const musicSearchKeyword = ref('') const musicSearchKeyword = ref('')
const musicLoading = ref(false) const musicLoading = ref(false)
@@ -278,10 +280,17 @@ const fetchPlaylistMusic = async (playlistId) => {
try { try {
const res = await getPlaylistById(playlistId) const res = await getPlaylistById(playlistId)
if (res.code === 200 && res.data.musics) { if (res.code === 200 && res.data.musics) {
playlistMusics.value = res.data.musics
selectedMusicIds.value = res.data.musics.map(m => m.id) selectedMusicIds.value = res.data.musics.map(m => m.id)
} else {
playlistMusics.value = []
selectedMusicIds.value = []
} }
} catch (error) { } catch (error) {
console.error('获取歌单音乐失败:', error) console.error('获取歌单音乐失败:', error)
playlistMusics.value = []
selectedMusicIds.value = []
showErrorOnce(error, '获取歌单音乐失败')
} }
} }
@@ -290,6 +299,8 @@ const managePlaylistMusic = async (row) => {
currentPlaylistId.value = row.id currentPlaylistId.value = row.id
currentPlaylistName.value = row.name currentPlaylistName.value = row.name
musicSearchKeyword.value = '' musicSearchKeyword.value = ''
playlistMusics.value = []
selectedMusicIds.value = []
musicDialogVisible.value = true musicDialogVisible.value = true
// 加载音乐列表和已选音乐 // 加载音乐列表和已选音乐
@@ -305,13 +316,16 @@ const addMusicToPlaylistLocal = async (musicId) => {
const res = await addMusicToPlaylist(currentPlaylistId.value, musicId) const res = await addMusicToPlaylist(currentPlaylistId.value, musicId)
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('添加成功') ElMessage.success('添加成功')
await fetchPlaylistMusic(currentPlaylistId.value) await Promise.all([
fetchPlaylistMusic(currentPlaylistId.value),
fetchPlaylistList()
])
} else { } else {
ElMessage.error(res.message || '添加失败') ElMessage.error(res.message || '添加失败')
} }
} catch (error) { } catch (error) {
console.error('添加音乐失败:', error) console.error('添加音乐失败:', error)
ElMessage.error('添加失败') showErrorOnce(error, '添加失败')
} }
} }
@@ -321,13 +335,16 @@ const removeMusicFromPlaylistLocal = async (musicId) => {
const res = await removeMusicFromPlaylist(currentPlaylistId.value, musicId) const res = await removeMusicFromPlaylist(currentPlaylistId.value, musicId)
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('移除成功') ElMessage.success('移除成功')
await fetchPlaylistMusic(currentPlaylistId.value) await Promise.all([
fetchPlaylistMusic(currentPlaylistId.value),
fetchPlaylistList()
])
} else { } else {
ElMessage.error(res.message || '移除失败') ElMessage.error(res.message || '移除失败')
} }
} catch (error) { } catch (error) {
console.error('移除音乐失败:', error) console.error('移除音乐失败:', error)
ElMessage.error('移除失败') showErrorOnce(error, '移除失败')
} }
} }
@@ -737,7 +754,7 @@ import { addMusicToPlaylist, removeMusicFromPlaylist } from '../../api/playlist'
<div class="selected-music-container"> <div class="selected-music-container">
<h3>已添加的音乐</h3> <h3>已添加的音乐</h3>
<el-table <el-table
:data="musicList.filter(m => selectedMusicIds.includes(m.id))" :data="playlistMusics"
stripe stripe
style="width: 100%" style="width: 100%"
empty-text="暂无音乐" empty-text="暂无音乐"