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:
@@ -31,7 +31,12 @@ public class MusicController {
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<MusicDTO> getMusicById(@PathVariable Long id) {
|
||||
MusicDTO musicDTO = musicService.getMusicById(id);
|
||||
Long userId = null;
|
||||
// 检查用户是否登录,但不强制要求登录
|
||||
if (StpUtil.isLogin()) {
|
||||
userId = StpUtil.getLoginIdAsLong();
|
||||
}
|
||||
MusicDTO musicDTO = musicService.getMusicById(id, userId);
|
||||
if (musicDTO == null) {
|
||||
// 如果音乐不存在,返回空数据而不是错误
|
||||
return Result.success(null);
|
||||
@@ -213,4 +218,20 @@ public class MusicController {
|
||||
MusicDTO musicDTO = musicService.playMusic(id);
|
||||
return Result.success(musicDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞/取消点赞音乐
|
||||
*
|
||||
* @param id 音乐ID
|
||||
* @return 响应结果
|
||||
*/
|
||||
@SaCheckLogin
|
||||
@PostMapping("/{id}/like")
|
||||
public Result<Boolean> toggleLikeMusic(@PathVariable Long id) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
boolean isLiked = musicService.toggleLikeMusic(id, userId);
|
||||
String message = isLiked ? "点赞成功" : "取消点赞成功";
|
||||
return Result.success(message, isLiked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ public class MusicDTO {
|
||||
*/
|
||||
private Boolean isCollected;
|
||||
|
||||
/**
|
||||
* 是否已点赞
|
||||
*/
|
||||
private Boolean isLiked;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@@ -107,4 +112,11 @@ public class MusicDTO {
|
||||
public void setCollected(boolean collected) {
|
||||
this.isCollected = collected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否已点赞
|
||||
*/
|
||||
public void setLiked(boolean liked) {
|
||||
this.isLiked = liked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.test.musichouduan.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "user_like_music", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"userId", "musicId"})
|
||||
})
|
||||
public class UserLikeMusic {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long userId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long musicId;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(nullable = false, updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -1,109 +1,109 @@
|
||||
package com.test.musichouduan.init;
|
||||
|
||||
import cn.dev33.satoken.secure.BCrypt;
|
||||
import com.test.musichouduan.entity.*;
|
||||
import com.test.musichouduan.repository.*;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据初始化器
|
||||
*/
|
||||
@Component
|
||||
public class DataInitializer implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private MusicTypeRepository musicTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private SingerTypeRepository singerTypeRepository;
|
||||
|
||||
@Autowired
|
||||
private PlaylistTypeRepository playlistTypeRepository;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void run(String... args) throws Exception {
|
||||
// 初始化管理员用户
|
||||
initAdminUser();
|
||||
|
||||
// 初始化音乐类型
|
||||
initMusicTypes();
|
||||
|
||||
// 初始化歌手类型
|
||||
initSingerTypes();
|
||||
|
||||
// 初始化歌单类型
|
||||
initPlaylistTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化管理员用户
|
||||
*/
|
||||
private void initAdminUser() {
|
||||
if (!userRepository.existsByUsername("admin")) {
|
||||
User admin = new User();
|
||||
admin.setUsername("admin");
|
||||
admin.setPassword(BCrypt.hashpw("123456"));
|
||||
admin.setNickname("管理员");
|
||||
admin.setGender(0);
|
||||
admin.setRole(1);
|
||||
admin.setStatus(1);
|
||||
userRepository.save(admin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化音乐类型
|
||||
*/
|
||||
private void initMusicTypes() {
|
||||
if (musicTypeRepository.count() == 0) {
|
||||
List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村");
|
||||
for (String name : typeNames) {
|
||||
MusicType type = new MusicType();
|
||||
type.setName(name);
|
||||
type.setDescription(name + "音乐");
|
||||
musicTypeRepository.save(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化歌手类型
|
||||
*/
|
||||
private void initSingerTypes() {
|
||||
if (singerTypeRepository.count() == 0) {
|
||||
List<String> typeNames = Arrays.asList("华语男歌手", "华语女歌手", "华语组合", "欧美男歌手", "欧美女歌手", "欧美组合", "日韩男歌手", "日韩女歌手", "日韩组合");
|
||||
for (String name : typeNames) {
|
||||
SingerType type = new SingerType();
|
||||
type.setName(name);
|
||||
type.setDescription(name);
|
||||
singerTypeRepository.save(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化歌单类型
|
||||
*/
|
||||
private void initPlaylistTypes() {
|
||||
if (playlistTypeRepository.count() == 0) {
|
||||
List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村", "轻音乐", "ACG");
|
||||
for (String name : typeNames) {
|
||||
PlaylistType type = new PlaylistType();
|
||||
type.setName(name);
|
||||
type.setDescription(name + "歌单");
|
||||
playlistTypeRepository.save(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//package com.test.musichouduan.init;
|
||||
//
|
||||
//import cn.dev33.satoken.secure.BCrypt;
|
||||
//import com.test.musichouduan.entity.*;
|
||||
//import com.test.musichouduan.repository.*;
|
||||
//
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.CommandLineRunner;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//
|
||||
//import java.util.Arrays;
|
||||
//import java.util.List;
|
||||
//
|
||||
///**
|
||||
// * 数据初始化器
|
||||
// */
|
||||
//@Component
|
||||
//public class DataInitializer implements CommandLineRunner {
|
||||
//
|
||||
// @Autowired
|
||||
// private UserRepository userRepository;
|
||||
//
|
||||
// @Autowired
|
||||
// private MusicTypeRepository musicTypeRepository;
|
||||
//
|
||||
// @Autowired
|
||||
// private SingerTypeRepository singerTypeRepository;
|
||||
//
|
||||
// @Autowired
|
||||
// private PlaylistTypeRepository playlistTypeRepository;
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void run(String... args) throws Exception {
|
||||
// // 初始化管理员用户
|
||||
// initAdminUser();
|
||||
//
|
||||
// // 初始化音乐类型
|
||||
// initMusicTypes();
|
||||
//
|
||||
// // 初始化歌手类型
|
||||
// initSingerTypes();
|
||||
//
|
||||
// // 初始化歌单类型
|
||||
// initPlaylistTypes();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 初始化管理员用户
|
||||
// */
|
||||
// private void initAdminUser() {
|
||||
// if (!userRepository.existsByUsername("admin")) {
|
||||
// User admin = new User();
|
||||
// admin.setUsername("admin");
|
||||
// admin.setPassword(BCrypt.hashpw("123456"));
|
||||
// admin.setNickname("管理员");
|
||||
// admin.setGender(0);
|
||||
// admin.setRole(1);
|
||||
// admin.setStatus(1);
|
||||
// userRepository.save(admin);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 初始化音乐类型
|
||||
// */
|
||||
// private void initMusicTypes() {
|
||||
// if (musicTypeRepository.count() == 0) {
|
||||
// List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村");
|
||||
// for (String name : typeNames) {
|
||||
// MusicType type = new MusicType();
|
||||
// type.setName(name);
|
||||
// type.setDescription(name + "音乐");
|
||||
// musicTypeRepository.save(type);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 初始化歌手类型
|
||||
// */
|
||||
// private void initSingerTypes() {
|
||||
// if (singerTypeRepository.count() == 0) {
|
||||
// List<String> typeNames = Arrays.asList("华语男歌手", "华语女歌手", "华语组合", "欧美男歌手", "欧美女歌手", "欧美组合", "日韩男歌手", "日韩女歌手", "日韩组合");
|
||||
// for (String name : typeNames) {
|
||||
// SingerType type = new SingerType();
|
||||
// type.setName(name);
|
||||
// type.setDescription(name);
|
||||
// singerTypeRepository.save(type);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 初始化歌单类型
|
||||
// */
|
||||
// private void initPlaylistTypes() {
|
||||
// if (playlistTypeRepository.count() == 0) {
|
||||
// List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村", "轻音乐", "ACG");
|
||||
// for (String name : typeNames) {
|
||||
// PlaylistType type = new PlaylistType();
|
||||
// type.setName(name);
|
||||
// type.setDescription(name + "歌单");
|
||||
// playlistTypeRepository.save(type);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -43,6 +43,15 @@ public interface UserCollectMusicRepository extends JpaRepository<UserCollectMus
|
||||
*/
|
||||
boolean existsByUserAndMusic(User user, Music music);
|
||||
|
||||
/**
|
||||
* 判断用户是否收藏了音乐
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param musicId 音乐ID
|
||||
* @return 是否收藏
|
||||
*/
|
||||
boolean existsByUserIdAndMusicId(Long userId, Long musicId);
|
||||
|
||||
/**
|
||||
* 根据用户统计收藏的音乐数量
|
||||
*
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.test.musichouduan.repository;
|
||||
|
||||
import com.test.musichouduan.entity.UserLikeMusic;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface UserLikeMusicRepository extends JpaRepository<UserLikeMusic, Long> {
|
||||
|
||||
/**
|
||||
* 根据用户ID和音乐ID查找点赞记录
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param musicId 音乐ID
|
||||
* @return 点赞记录
|
||||
*/
|
||||
Optional<UserLikeMusic> findByUserIdAndMusicId(Long userId, Long musicId);
|
||||
|
||||
/**
|
||||
* 检查用户是否点赞了某音乐
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param musicId 音乐ID
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByUserIdAndMusicId(Long userId, Long musicId);
|
||||
}
|
||||
@@ -13,6 +13,15 @@ import java.util.concurrent.CompletableFuture;
|
||||
*/
|
||||
public interface MusicService {
|
||||
|
||||
/**
|
||||
* 根据ID获取音乐,并根据用户ID判断是否收藏和点赞
|
||||
*
|
||||
* @param id 音乐ID
|
||||
* @param userId 用户ID (可以为null)
|
||||
* @return 音乐DTO
|
||||
*/
|
||||
MusicDTO getMusicById(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 根据ID获取音乐
|
||||
*
|
||||
@@ -133,4 +142,13 @@ public interface MusicService {
|
||||
* @return CompletableFuture 包装的音乐DTO列表
|
||||
*/
|
||||
CompletableFuture<List<MusicDTO>> updateHotMusicCache();
|
||||
|
||||
/**
|
||||
* 切换音乐点赞状态
|
||||
*
|
||||
* @param musicId 音乐ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否点赞成功 (true: 点赞, false: 取消点赞)
|
||||
*/
|
||||
boolean toggleLikeMusic(Long musicId, Long userId);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.test.musichouduan.entity.Music;
|
||||
import com.test.musichouduan.entity.MusicType;
|
||||
import com.test.musichouduan.entity.Singer;
|
||||
import com.test.musichouduan.entity.User;
|
||||
import com.test.musichouduan.entity.UserCollectMusic;
|
||||
import com.test.musichouduan.entity.UserLikeMusic;
|
||||
import com.test.musichouduan.entity.UserMusic;
|
||||
import com.test.musichouduan.exception.BusinessException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
@@ -72,7 +74,10 @@ public class MusicServiceImpl implements MusicService {
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private UserMusicRepository userMusicRepository;
|
||||
private UserCollectMusicRepository userCollectMusicRepository;
|
||||
|
||||
@Autowired
|
||||
private UserLikeMusicRepository userLikeMusicRepository;
|
||||
|
||||
@Autowired
|
||||
private PlayHistoryRepository playHistoryRepository;
|
||||
@@ -81,13 +86,19 @@ public class MusicServiceImpl implements MusicService {
|
||||
private FileService fileService;
|
||||
|
||||
@Override
|
||||
public MusicDTO getMusicById(Long id) {
|
||||
public MusicDTO getMusicById(Long id, Long userId) {
|
||||
// 查找音乐,如果不存在则返回null
|
||||
return musicRepository.findById(id)
|
||||
.map(this::convertToDTO)
|
||||
.map(music -> convertToDTO(music, userId))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MusicDTO getMusicById(Long id) {
|
||||
// 对于未登录用户或不需要用户状态的场景,直接调用新方法并传入null
|
||||
return getMusicById(id, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<MusicDTO> getMusicList(Integer page, Integer size, String keyword, Long typeId) {
|
||||
// 构建查询条件
|
||||
@@ -463,35 +474,37 @@ public class MusicServiceImpl implements MusicService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean toggleCollectMusic(Long id, Long userId) {
|
||||
// 获取用户
|
||||
Optional<User> userOpt = userRepository.findById(userId);
|
||||
if (!userOpt.isPresent()) {
|
||||
// 如果用户不存在,返回false
|
||||
return false;
|
||||
}
|
||||
User user = userOpt.get();
|
||||
public boolean toggleCollectMusic(Long musicId, Long userId) {
|
||||
// 直接通过ID判断是否存在,避免查询完整实体
|
||||
boolean isCollected = userCollectMusicRepository.existsByUserIdAndMusicId(userId, musicId);
|
||||
|
||||
// 获取音乐
|
||||
Optional<Music> musicOpt = musicRepository.findById(id);
|
||||
if (!musicOpt.isPresent()) {
|
||||
// 如果音乐不存在,返回false
|
||||
return false;
|
||||
}
|
||||
Music music = musicOpt.get();
|
||||
|
||||
// 检查是否已收藏
|
||||
boolean isCollected = userMusicRepository.existsByUserAndMusic(user, music);
|
||||
Music music = musicRepository.findById(musicId)
|
||||
.orElseThrow(() -> new BusinessException("音乐不存在"));
|
||||
|
||||
if (isCollected) {
|
||||
// 如果已收藏,则取消收藏
|
||||
userMusicRepository.uncollectMusic(user.getId(), music.getId());
|
||||
} else {
|
||||
// 如果未收藏,则收藏
|
||||
userMusicRepository.collectMusic(user.getId(), music.getId());
|
||||
}
|
||||
// 已收藏,取消收藏
|
||||
User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("用户不存在"));
|
||||
UserCollectMusic collect = userCollectMusicRepository.findByUserAndMusic(user, music)
|
||||
.orElseThrow(() -> new BusinessException("收藏记录不存在"));
|
||||
userCollectMusicRepository.delete(collect);
|
||||
|
||||
return !isCollected; // 返回当前收藏状态,true表示已收藏,false表示未收藏
|
||||
int currentCollectCount = music.getCollectCount() != null ? music.getCollectCount() : 0;
|
||||
music.setCollectCount(Math.max(0, currentCollectCount - 1));
|
||||
musicRepository.save(music);
|
||||
return false; // 返回 "未收藏" 状态
|
||||
} else {
|
||||
// 未收藏,执行收藏
|
||||
User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("用户不存在"));
|
||||
UserCollectMusic newCollect = new UserCollectMusic();
|
||||
newCollect.setUser(user);
|
||||
newCollect.setMusic(music);
|
||||
userCollectMusicRepository.save(newCollect);
|
||||
|
||||
int currentCollectCount = music.getCollectCount() != null ? music.getCollectCount() : 0;
|
||||
music.setCollectCount(currentCollectCount + 1);
|
||||
musicRepository.save(music);
|
||||
return true; // 返回 "已收藏" 状态
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -501,24 +514,24 @@ public class MusicServiceImpl implements MusicService {
|
||||
.orElseThrow(() -> new BusinessException("用户不存在"));
|
||||
|
||||
// 获取用户收藏的音乐
|
||||
Page<UserMusic> userMusicPage = userMusicRepository.findCollectedMusic(
|
||||
user.getId(),
|
||||
PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "collectTime"))
|
||||
Page<UserCollectMusic> userCollectMusicPage = userCollectMusicRepository.findByUser(
|
||||
user,
|
||||
PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"))
|
||||
);
|
||||
|
||||
// 转换为DTO
|
||||
List<MusicDTO> musicDTOs = userMusicPage.getContent().stream()
|
||||
.map(userMusic -> {
|
||||
MusicDTO musicDTO = convertToDTO(userMusic.getMusic());
|
||||
List<MusicDTO> musicDTOs = userCollectMusicPage.getContent().stream()
|
||||
.map(userCollectMusic -> {
|
||||
MusicDTO musicDTO = convertToDTO(userCollectMusic.getMusic());
|
||||
// 设置收藏时间
|
||||
musicDTO.setCollectTime(userMusic.getCollectTime());
|
||||
musicDTO.setCollectTime(userCollectMusic.getCreateTime());
|
||||
return musicDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new PageResult<>(
|
||||
musicDTOs,
|
||||
userMusicPage.getTotalElements(),
|
||||
userCollectMusicPage.getTotalElements(),
|
||||
page,
|
||||
size
|
||||
);
|
||||
@@ -539,8 +552,6 @@ public class MusicServiceImpl implements MusicService {
|
||||
// 增加播放次数
|
||||
long currentPlayCount = music.getPlayCount() != null ? music.getPlayCount() : 0;
|
||||
music.setPlayCount(currentPlayCount + 1);
|
||||
// 根据要求,将点赞数与播放次数同步
|
||||
music.setLikeCount((int) (currentPlayCount + 1));
|
||||
musicRepository.save(music);
|
||||
|
||||
// 如果用户已登录,记录播放历史
|
||||
@@ -560,6 +571,34 @@ public class MusicServiceImpl implements MusicService {
|
||||
return musicRepository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean toggleLikeMusic(Long musicId, Long userId) {
|
||||
Music music = musicRepository.findById(musicId)
|
||||
.orElseThrow(() -> new BusinessException("音乐不存在"));
|
||||
|
||||
Optional<UserLikeMusic> likeOpt = userLikeMusicRepository.findByUserIdAndMusicId(userId, musicId);
|
||||
|
||||
if (likeOpt.isPresent()) {
|
||||
// 已点赞,取消点赞
|
||||
userLikeMusicRepository.delete(likeOpt.get());
|
||||
int currentLikeCount = music.getLikeCount() != null ? music.getLikeCount() : 0;
|
||||
music.setLikeCount(Math.max(0, currentLikeCount - 1));
|
||||
musicRepository.save(music);
|
||||
return false; // 返回 "未点赞" 状态
|
||||
} else {
|
||||
// 未点赞,执行点赞
|
||||
UserLikeMusic newLike = new UserLikeMusic();
|
||||
newLike.setUserId(userId);
|
||||
newLike.setMusicId(musicId);
|
||||
userLikeMusicRepository.save(newLike);
|
||||
int currentLikeCount = music.getLikeCount() != null ? music.getLikeCount() : 0;
|
||||
music.setLikeCount(currentLikeCount + 1);
|
||||
musicRepository.save(music);
|
||||
return true; // 返回 "已点赞" 状态
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将实体转换为DTO
|
||||
*
|
||||
@@ -567,52 +606,49 @@ public class MusicServiceImpl implements MusicService {
|
||||
* @return 音乐DTO
|
||||
*/
|
||||
private MusicDTO convertToDTO(Music music) {
|
||||
// 保留此方法以兼容不需要用户状态的转换
|
||||
return convertToDTO(music, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将实体转换为DTO,并根据用户ID判断是否收藏和点赞
|
||||
*
|
||||
* @param music 音乐实体
|
||||
* @param userId 用户ID (可以为null)
|
||||
* @return 音乐DTO
|
||||
*/
|
||||
private MusicDTO convertToDTO(Music music, Long userId) {
|
||||
MusicDTO musicDTO = new MusicDTO();
|
||||
BeanUtils.copyProperties(music, musicDTO);
|
||||
|
||||
// 确保专辑字段正确复制
|
||||
musicDTO.setAlbum(music.getAlbum());
|
||||
|
||||
// 设置类型ID列表
|
||||
if (music.getTypes() != null) {
|
||||
List<Long> typeIds = music.getTypes().stream()
|
||||
.map(MusicType::getId)
|
||||
.collect(Collectors.toList());
|
||||
musicDTO.setTypeIds(typeIds);
|
||||
|
||||
// 设置类型名称列表
|
||||
List<String> typeNames = music.getTypes().stream()
|
||||
.map(MusicType::getName)
|
||||
.collect(Collectors.toList());
|
||||
musicDTO.setTypeNames(typeNames);
|
||||
// 设置类型ID和名称列表
|
||||
if (!CollectionUtils.isEmpty(music.getTypes())) {
|
||||
musicDTO.setTypeIds(music.getTypes().stream().map(MusicType::getId).collect(Collectors.toList()));
|
||||
musicDTO.setTypeNames(music.getTypes().stream().map(MusicType::getName).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
// 设置歌手ID列表
|
||||
if (music.getSingers() != null) {
|
||||
List<Long> singerIds = music.getSingers().stream()
|
||||
.map(Singer::getId)
|
||||
.collect(Collectors.toList());
|
||||
musicDTO.setSingerIds(singerIds);
|
||||
|
||||
// 设置歌手名称列表
|
||||
List<String> singerNames = music.getSingers().stream()
|
||||
.map(Singer::getName)
|
||||
.collect(Collectors.toList());
|
||||
// 设置歌手ID和名称列表
|
||||
if (!CollectionUtils.isEmpty(music.getSingers())) {
|
||||
musicDTO.setSingerIds(music.getSingers().stream().map(Singer::getId).collect(Collectors.toList()));
|
||||
List<String> singerNames = music.getSingers().stream().map(Singer::getName).collect(Collectors.toList());
|
||||
musicDTO.setSingerNames(singerNames);
|
||||
|
||||
// 设置歌手名称字符串(用于前端显示)
|
||||
if (!singerNames.isEmpty()) {
|
||||
musicDTO.setSinger(String.join(", ", singerNames));
|
||||
}
|
||||
musicDTO.setSinger(String.join("、", singerNames));
|
||||
}
|
||||
|
||||
// 检查当前登录用户是否已收藏该音乐
|
||||
if (StpUtil.isLogin()) {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
boolean isCollected = userMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
||||
// 如果传入了用户ID,则查询该用户的收藏和点赞状态
|
||||
if (userId != null) {
|
||||
boolean isCollected = userCollectMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
||||
musicDTO.setCollected(isCollected);
|
||||
|
||||
boolean isLiked = userLikeMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
||||
musicDTO.setLiked(isLiked);
|
||||
} else {
|
||||
// 如果未传入用户ID,则默认为未收藏和未点赞
|
||||
musicDTO.setCollected(false);
|
||||
musicDTO.setLiked(false);
|
||||
}
|
||||
|
||||
return musicDTO;
|
||||
|
||||
@@ -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 页码
|
||||
|
||||
@@ -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)
|
||||
|
||||
118
sql/music_db.sql
118
sql/music_db.sql
@@ -11,7 +11,7 @@
|
||||
Target Server Version : 80041 (8.0.41)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 23/07/2025 22:59:43
|
||||
Date: 25/07/2025 22:22:53
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -44,42 +44,37 @@ CREATE TABLE `comment` (
|
||||
`content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '评论内容',
|
||||
`user_id` bigint NOT NULL COMMENT '评论用户ID',
|
||||
`target_id` bigint NOT NULL COMMENT '评论目标ID',
|
||||
`target_type` int NOT NULL,
|
||||
`target_type` int NOT NULL COMMENT '评论目标类型:1-音乐,2-歌单,3-歌手',
|
||||
`parent_id` bigint NULL DEFAULT NULL COMMENT '父评论ID',
|
||||
`status` int NULL DEFAULT NULL,
|
||||
`status` int NULL DEFAULT NULL COMMENT '状态:0-禁用,1-正常',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||
INDEX `idx_target`(`target_id` ASC, `target_type` ASC) USING BTREE,
|
||||
INDEX `idx_parent_id`(`parent_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FK8kcum44fvpupyw6f5baccx25c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '评论表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_parent_id`(`parent_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 56 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '评论表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for music
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `music`;
|
||||
CREATE TABLE `music` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '音乐ID',
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐名称',
|
||||
`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '封面URL',
|
||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐文件URL',
|
||||
`lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '歌词',
|
||||
`duration` int NULL DEFAULT 0 COMMENT '时长(秒)',
|
||||
`album` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
|
||||
|
||||
-- Interaction and Hot Score Fields
|
||||
`play_count` bigint NULL DEFAULT 0 COMMENT '播放次数',
|
||||
`like_count` int NULL DEFAULT 0 COMMENT '点赞数',
|
||||
`collect_count` int NULL DEFAULT 0 COMMENT '收藏数',
|
||||
`comment_count` int NULL DEFAULT 0 COMMENT '评论数',
|
||||
`hot_score` double NULL DEFAULT 0.0 COMMENT '热度分数',
|
||||
|
||||
-- Timestamps
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '音乐ID',
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐名称',
|
||||
`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '封面URL',
|
||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐文件URL',
|
||||
`lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '歌词',
|
||||
`duration` int NULL DEFAULT 0 COMMENT '时长(秒)',
|
||||
`play_count` bigint NULL DEFAULT 0 COMMENT '播放次数',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`album` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
|
||||
`like_count` int NULL DEFAULT NULL COMMENT '点赞数',
|
||||
`collect_count` int NULL DEFAULT NULL COMMENT '收藏数',
|
||||
`comment_count` int NULL DEFAULT NULL COMMENT '评论数',
|
||||
`hot_score` double NULL DEFAULT NULL COMMENT '热度分数',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -121,9 +116,7 @@ CREATE TABLE `music_type_relation` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_music_type`(`music_id` ASC, `type_id` ASC) USING BTREE,
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FK2i7xdrmrh0l6thp9u2r16fdcm` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKjtxip1yvwn66p4cbpycekychq` FOREIGN KEY (`type_id`) REFERENCES `music_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐-类型关联表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -137,10 +130,8 @@ CREATE TABLE `play_history` (
|
||||
`play_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '播放时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKm05jb66wc5epn38vuwm55o933` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKt6cp1qv95qi4abyn69soyvibk` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '播放历史表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '播放历史表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for playlist
|
||||
@@ -159,10 +150,8 @@ CREATE TABLE `playlist` (
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_creator_id`(`creator_id` ASC) USING BTREE,
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKi45kpenvb301c9yb1labp8b4j` FOREIGN KEY (`creator_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKttnmgs0esm9njqa0g52mbp48` FOREIGN KEY (`type_id`) REFERENCES `playlist_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for playlist_music
|
||||
@@ -176,9 +165,7 @@ CREATE TABLE `playlist_music` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_playlist_music`(`playlist_id` ASC, `music_id` ASC) USING BTREE,
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FK5g0xtl5e89uycye0jo1ll65sq` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKq9o07ljjk03aeeqt0q9lwhndk` FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单-音乐关联表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -208,8 +195,7 @@ CREATE TABLE `singer` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKdwhlvo45iuspxcjg0gax5exwm` FOREIGN KEY (`type_id`) REFERENCES `singer_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌手表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -220,9 +206,7 @@ CREATE TABLE `singer_music` (
|
||||
`singer_id` bigint NOT NULL,
|
||||
`music_id` bigint NOT NULL,
|
||||
PRIMARY KEY (`singer_id`, `music_id`) USING BTREE,
|
||||
INDEX `FKk0fdv208e2ulhcxd9gge63h6j`(`music_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKf33uki3h3ftg9ne16xr4n1srp` FOREIGN KEY (`singer_id`) REFERENCES `singer` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKk0fdv208e2ulhcxd9gge63h6j` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
INDEX `FKk0fdv208e2ulhcxd9gge63h6j`(`music_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -289,10 +273,8 @@ CREATE TABLE `user_collect_music` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_user_music`(`user_id` ASC, `music_id` ASC) USING BTREE,
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FK1bm2wy4dgmhdfvp6k9fhqpf73` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKt8w479d40yle3jxmqiovm6quo` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏音乐表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏音乐表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user_collect_playlist
|
||||
@@ -305,10 +287,8 @@ CREATE TABLE `user_collect_playlist` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_user_playlist`(`user_id` ASC, `playlist_id` ASC) USING BTREE,
|
||||
INDEX `idx_playlist_id`(`playlist_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKe4f1odrrb8yq287v9gwsbq5px` FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKqxg6amofxpxuxf6uwjebb5jak` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌单表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_playlist_id`(`playlist_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌单表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user_collect_singer
|
||||
@@ -321,10 +301,22 @@ CREATE TABLE `user_collect_singer` (
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_user_singer`(`user_id` ASC, `singer_id` ASC) USING BTREE,
|
||||
INDEX `idx_singer_id`(`singer_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKlvx6pnysffce263knm6iivjjj` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKn8hu81ynti2nku5p7nsh6mk1k` FOREIGN KEY (`singer_id`) REFERENCES `singer` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌手表' ROW_FORMAT = Dynamic;
|
||||
INDEX `idx_singer_id`(`singer_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌手表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user_like_music
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `user_like_music`;
|
||||
CREATE TABLE `user_like_music` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`music_id` bigint NOT NULL COMMENT '音乐ID',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '点赞时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_user_music`(`user_id` ASC, `music_id` ASC) USING BTREE,
|
||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户点赞音乐表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user_music
|
||||
@@ -337,10 +329,8 @@ CREATE TABLE `user_music` (
|
||||
`user_id` bigint NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `FKb53nc2rlyaotl1socy90u0v8`(`music_id` ASC) USING BTREE,
|
||||
INDEX `FKq3jkqxxm4lxvoaauy93dq1hjl`(`user_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKb53nc2rlyaotl1socy90u0v8` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `FKq3jkqxxm4lxvoaauy93dq1hjl` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
INDEX `FKq3jkqxxm4lxvoaauy93dq1hjl`(`user_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user_playlist
|
||||
@@ -353,8 +343,7 @@ CREATE TABLE `user_playlist` (
|
||||
`user_id` bigint NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `FK7k6xercebs1wg014xb49hw3h0`(`playlist_id` ASC) USING BTREE,
|
||||
INDEX `FKmofufj03yw1wqauec6vrdnfw1`(`user_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKmofufj03yw1wqauec6vrdnfw1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
INDEX `FKmofufj03yw1wqauec6vrdnfw1`(`user_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -368,8 +357,7 @@ CREATE TABLE `user_singer` (
|
||||
`user_id` bigint NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `FKacl5uu14x3io8qygn0cp27nvb`(`singer_id` ASC) USING BTREE,
|
||||
INDEX `FKnogaivkt6y4jy5vbt85tu8qj0`(`user_id` ASC) USING BTREE,
|
||||
CONSTRAINT `FKnogaivkt6y4jy5vbt85tu8qj0` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
INDEX `FKnogaivkt6y4jy5vbt85tu8qj0`(`user_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
Reference in New Issue
Block a user