Compare commits
2 Commits
6f0e59cd28
...
414d214fa9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
414d214fa9 | ||
|
|
24eb4ec5d6 |
@@ -54,6 +54,16 @@ public class MusicDTO {
|
|||||||
*/
|
*/
|
||||||
private Long playCount;
|
private Long playCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点赞数
|
||||||
|
*/
|
||||||
|
private Integer likeCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收藏数
|
||||||
|
*/
|
||||||
|
private Integer collectCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 歌手列表
|
* 歌手列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -650,6 +650,10 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
MusicDTO musicDTO = new MusicDTO();
|
MusicDTO musicDTO = new MusicDTO();
|
||||||
BeanUtils.copyProperties(music, musicDTO);
|
BeanUtils.copyProperties(music, musicDTO);
|
||||||
|
|
||||||
|
// 兜底互动计数,避免前端出现 null
|
||||||
|
musicDTO.setLikeCount(music.getLikeCount() != null ? music.getLikeCount() : 0);
|
||||||
|
musicDTO.setCollectCount(music.getCollectCount() != null ? music.getCollectCount() : 0);
|
||||||
|
|
||||||
// 确保专辑字段正确复制
|
// 确保专辑字段正确复制
|
||||||
musicDTO.setAlbum(music.getAlbum());
|
musicDTO.setAlbum(music.getAlbum());
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,16 @@
|
|||||||
<span class="label">发行日期:</span>
|
<span class="label">发行日期:</span>
|
||||||
<span class="value">{{ music.releaseDate || '-' }}</span>
|
<span class="value">{{ music.releaseDate || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="meta-item">
|
||||||
|
<span class="label">点赞数:</span>
|
||||||
|
<span class="value">{{ music.likeCount ?? 0 }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meta-item">
|
||||||
|
<span class="label">收藏数:</span>
|
||||||
|
<span class="value">{{ music.collectCount ?? 0 }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="music-actions">
|
<div class="music-actions">
|
||||||
@@ -321,7 +331,11 @@ const fetchMusicDetail = async () => {
|
|||||||
const res = await getMusicById(id)
|
const res = await getMusicById(id)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
music.value = res.data
|
music.value = {
|
||||||
|
...res.data,
|
||||||
|
likeCount: res.data.likeCount ?? 0,
|
||||||
|
collectCount: res.data.collectCount ?? 0
|
||||||
|
}
|
||||||
// 获取音乐状态
|
// 获取音乐状态
|
||||||
fetchMusicStatus()
|
fetchMusicStatus()
|
||||||
} else {
|
} else {
|
||||||
@@ -543,6 +557,12 @@ const toggleCollect = async () => {
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
// 后端直接返回了最新的收藏状态 (true/false),直接赋值即可
|
// 后端直接返回了最新的收藏状态 (true/false),直接赋值即可
|
||||||
music.value.collected = res.data
|
music.value.collected = res.data
|
||||||
|
// 仅在操作成功时同步更新本地收藏数
|
||||||
|
if (music.value.collected) {
|
||||||
|
music.value.collectCount = (music.value.collectCount || 0) + 1
|
||||||
|
} else {
|
||||||
|
music.value.collectCount = Math.max(0, (music.value.collectCount || 0) - 1)
|
||||||
|
}
|
||||||
ElMessage.success(res.message || (music.value.collected ? '收藏成功' : '已取消收藏'))
|
ElMessage.success(res.message || (music.value.collected ? '收藏成功' : '已取消收藏'))
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.message || '操作失败')
|
ElMessage.error(res.message || '操作失败')
|
||||||
|
|||||||
@@ -29,6 +29,39 @@ const editForm = reactive({
|
|||||||
gender: 0,
|
gender: 0,
|
||||||
introduction: ''
|
introduction: ''
|
||||||
})
|
})
|
||||||
|
const validateAvatar = (_rule, value, callback) => {
|
||||||
|
if (!value || !String(value).trim()) {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const avatar = String(value).trim()
|
||||||
|
|
||||||
|
// 兼容站内相对路径(如 /upload/xx、./xx、../xx、images/a.png)
|
||||||
|
const hasScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(avatar)
|
||||||
|
if (!hasScheme) {
|
||||||
|
const isRelativePath = /^(\/?[^\s]+)$/.test(avatar) && !avatar.startsWith('//')
|
||||||
|
if (isRelativePath) {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback(new Error('请输入有效头像地址(http/https 或相对路径)'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = new URL(avatar)
|
||||||
|
if (url.protocol === 'http:' || url.protocol === 'https:') {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(new Error('请输入有效头像地址(http/https 或相对路径)'))
|
||||||
|
}
|
||||||
|
|
||||||
const editFormRules = {
|
const editFormRules = {
|
||||||
nickname: [
|
nickname: [
|
||||||
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
||||||
@@ -38,7 +71,7 @@ const editFormRules = {
|
|||||||
{ pattern: /^\S+@\S+\.\S+$/, message: '请输入正确的邮箱地址', trigger: 'blur' }
|
{ pattern: /^\S+@\S+\.\S+$/, message: '请输入正确的邮箱地址', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
avatar: [
|
avatar: [
|
||||||
{ pattern: /^(https?:\/\/)?[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?$/, message: '请输入正确的URL地址', trigger: 'blur' }
|
{ validator: validateAvatar, trigger: 'blur' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
const editFormRef = ref(null)
|
const editFormRef = ref(null)
|
||||||
|
|||||||
Reference in New Issue
Block a user