feat(playlist): 添加歌单编辑功能

- 在前端 PlaylistDetail组件中添加编辑歌单的对话框和相关逻辑
- 在后端 PlaylistServiceImpl 中实现更新歌单信息和封面的方法
- 优化封面上传逻辑,将物理路径转换为相对路径
This commit is contained in:
ikmkj
2025-07-27 15:55:44 +08:00
parent ced0a0931d
commit e024184bbd
2 changed files with 98 additions and 5 deletions

View File

@@ -36,6 +36,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Predicate;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -237,7 +238,8 @@ public class PlaylistServiceImpl implements PlaylistService {
// 上传封面 // 上传封面
String coverUrl = null; String coverUrl = null;
if (cover != null && !cover.isEmpty()) { if (cover != null && !cover.isEmpty()) {
coverUrl = fileService.uploadImage(cover); String coverPhysicalPath = fileService.uploadImage(cover);
coverUrl = coverPhysicalPath.replace(System.getProperty("user.dir") + File.separator + "music-houduan", "").replace(File.separator, "/");
} }
// 创建歌单实体 // 创建歌单实体
@@ -286,7 +288,8 @@ public class PlaylistServiceImpl implements PlaylistService {
} }
// 上传新封面 // 上传新封面
String coverUrl = fileService.uploadImage(cover); String coverPhysicalPath = fileService.uploadImage(cover);
String coverUrl = coverPhysicalPath.replace(System.getProperty("user.dir") + File.separator + "music-houduan", "").replace(File.separator, "/");
playlist.setCover(coverUrl); playlist.setCover(coverUrl);
} }

View File

@@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router'
import { usePlayerStore } from '../stores/player' import { usePlayerStore } from '../stores/player'
import { useUserStore } from '../stores/user' import { useUserStore } from '../stores/user'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getPlaylistById, toggleCollectPlaylist, deletePlaylist as apiDeletePlaylist, isPlaylistCollected } from '../api/playlist' import { getPlaylistById, toggleCollectPlaylist, deletePlaylist as apiDeletePlaylist, isPlaylistCollected, updatePlaylist } from '../api/playlist'
import { getMusicStatus } from '../api/music' import { getMusicStatus } from '../api/music'
import { getCommentList, addComment, deleteComment as apiDeleteComment } from '../api/comment' import { getCommentList, addComment, deleteComment as apiDeleteComment } from '../api/comment'
import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket' // 导入 WebSocket 工具 import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket' // 导入 WebSocket 工具
@@ -49,6 +49,20 @@ const isCollected = ref(false)
// 是否是创建者 // 是否是创建者
const isCreator = ref(false) const isCreator = ref(false)
// 编辑模态框可见性
const editDialogVisible = ref(false)
// 编辑表单数据
const editForm = ref({
id: null,
name: '',
description: '',
cover: null
})
// 封面预览 URL
const coverPreview = ref('')
// 获取歌单详情 // 获取歌单详情
const fetchPlaylistDetail = async () => { const fetchPlaylistDetail = async () => {
loading.value = true loading.value = true
@@ -297,8 +311,42 @@ const editPlaylist = () => {
return return
} }
// 实际应用中,这里应该跳转到编辑页面或打开编辑对话框 // 初始化编辑表单
ElMessage.info('编辑歌单功能开发中') editForm.value = {
id: playlist.value.id,
name: playlist.value.name,
description: playlist.value.description,
cover: null
}
coverPreview.value = playlist.value.cover
editDialogVisible.value = true
}
// 处理封面选择
const handleCoverChange = (file) => {
editForm.value.cover = file.raw
coverPreview.value = URL.createObjectURL(file.raw)
}
// 提交编辑
const submitEdit = async () => {
try {
const res = await updatePlaylist(editForm.value.id, {
name: editForm.value.name,
description: editForm.value.description
}, editForm.value.cover)
if (res.code === 200) {
ElMessage.success('歌单更新成功')
editDialogVisible.value = false
fetchPlaylistDetail()
} else {
ElMessage.error(res.message || '更新失败')
}
} catch (error) {
console.error('更新歌单失败:', error)
ElMessage.error('更新失败,请稍后重试')
}
} }
// 删除歌单 // 删除歌单
@@ -599,10 +647,52 @@ onUnmounted(() => {
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<!-- 编辑歌单对话框 -->
<el-dialog v-model="editDialogVisible" title="编辑歌单" width="500px">
<el-form :model="editForm" label-width="80px">
<el-form-item label="歌单名称">
<el-input v-model="editForm.name" />
</el-form-item>
<el-form-item label="歌单描述">
<el-input v-model="editForm.description" type="textarea" :rows="3" />
</el-form-item>
<el-form-item label="封面">
<el-upload
class="cover-uploader"
action="#"
:show-file-list="false"
:auto-upload="false"
@change="handleCoverChange"
>
<img v-if="coverPreview" :src="coverPreview" class="cover" />
<el-icon v-else class="cover-uploader-icon"><plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitEdit">确定</el-button>
</span>
</template>
</el-dialog>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.cover-uploader .cover {
width: 178px;
height: 178px;
display: block;
}
.cover-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
.playlist-detail-container { .playlist-detail-container {
padding: 20px; padding: 20px;
min-height: calc(100vh - 140px); min-height: calc(100vh - 140px);