feat(music): 添加点赞功能并优化音乐解析
- 在 MusicPlayer 组件中添加点赞功能,使用 Check 和 Pointer 图标表示点赞状态 - 引入 toggleLikeMusic API 接口 - 优化歌词解析逻辑,提高代码可读性和性能 - 修改 UserLikeMusic 实体类,使用复合主键设计
This commit is contained in:
@@ -1,31 +1,28 @@
|
|||||||
package com.test.musichouduan.entity;
|
package com.test.musichouduan.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
/**
|
|
||||||
* 用户点赞音乐实体类
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Entity
|
|
||||||
@Table(name = "user_like_music", uniqueConstraints = {
|
|
||||||
@UniqueConstraint(columnNames = {"userId", "musicId"})
|
|
||||||
})
|
|
||||||
public class UserLikeMusic {
|
|
||||||
|
|
||||||
@Id
|
@Entity
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@Data
|
||||||
|
@Table(name = "user_like_music")
|
||||||
|
@IdClass(UserLikeMusic.class)
|
||||||
|
public class UserLikeMusic implements Serializable {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Id
|
||||||
|
@Column(name = "user_id")
|
||||||
private Long userId;
|
private Long userId;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Id
|
||||||
|
@Column(name = "music_id")
|
||||||
private Long musicId;
|
private Long musicId;
|
||||||
|
|
||||||
@CreationTimestamp
|
|
||||||
@Column(nullable = false, updatable = false)
|
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
<el-tooltip :content="currentMusic.liked ? '取消点赞' : '点赞'" placement="top">
|
<el-tooltip :content="currentMusic.liked ? '取消点赞' : '点赞'" placement="top">
|
||||||
<el-button circle @click="toggleLike">
|
<el-button circle @click="toggleLike">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="currentMusic.liked ? 'Pointer' : 'Pointer'" />
|
<component :is="currentMusic.liked ? 'Check' : 'Pointer'" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@@ -296,11 +296,11 @@ import { ref, computed, watch, nextTick } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { 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 { processMusicUrl, toggleCollectMusic, getMusicStatus } from '../api/music'
|
import { processMusicUrl, toggleCollectMusic, getMusicStatus, toggleLikeMusic } from '../api/music'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import {
|
import {
|
||||||
VideoPlay, VideoPause, Back, Right, List, Close, Delete,
|
VideoPlay, VideoPause, Back, Right, List, Close, Delete,
|
||||||
Mute, VideoCamera, Microphone, Star, StarFilled, ArrowDown, Pointer
|
Mute, VideoCamera, Microphone, Star, StarFilled, ArrowDown, Pointer, Check
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -380,26 +380,27 @@ const loopModeText = computed(() => {
|
|||||||
|
|
||||||
// 解析歌词
|
// 解析歌词
|
||||||
const parsedLyric = computed(() => {
|
const parsedLyric = computed(() => {
|
||||||
if (!currentMusic.value || !currentMusic.value.lyric) return []
|
if (!currentMusic.value || !currentMusic.value.lyric) return [];
|
||||||
const lyric = currentMusic.value.lyric
|
const lyric = currentMusic.value.lyric;
|
||||||
const lines = lyric.split('\n')
|
const lines = lyric.split('\n');
|
||||||
const timeRegExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/g
|
const result = [];
|
||||||
const result = []
|
const timeRegExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/g;
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const timeMatches = [...line.matchAll(timeRegExp)]
|
const text = line.replace(timeRegExp, '').trim();
|
||||||
if (timeMatches.length > 0) {
|
if (text) {
|
||||||
const match = timeMatches
|
timeRegExp.lastIndex = 0;
|
||||||
const min = parseInt(match)
|
let match;
|
||||||
const sec = parseInt(match)
|
while ((match = timeRegExp.exec(line)) !== null) {
|
||||||
const ms = parseInt(match)
|
const min = parseInt(match, 10);
|
||||||
const time = min * 60 + sec + ms / 1000
|
const sec = parseInt(match, 10);
|
||||||
let text = line.replace(timeRegExp, '').trim()
|
const ms = parseInt((match || '0').padEnd(3, '0'), 10);
|
||||||
if (text) {
|
const time = min * 60 + sec + ms / 1000;
|
||||||
result.push({ time, text })
|
result.push({ time, text });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.sort((a, b) => a.time - b.time)
|
return result.sort((a, b) => a.time - b.time);
|
||||||
})
|
})
|
||||||
|
|
||||||
// 格式化时间
|
// 格式化时间
|
||||||
|
|||||||
Reference in New Issue
Block a user