feat: 新增收藏/取消收藏专辑 & 歌手页优化

This commit is contained in:
imsyy
2023-04-10 18:29:40 +08:00
parent d291e86998
commit 18359d69d2
8 changed files with 293 additions and 70 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "splayer",
"version": "1.0.3",
"version": "1.0.4",
"private": true,
"author": "imsyy",
"home": "https://imsyy.top",

View File

@@ -48,3 +48,20 @@ export const getToplist = (detail = true) => {
url: `/toplist${detail ? "/detail" : null}`,
});
};
/**
* 收藏/取消收藏专辑
* @param {number} t - 操作类型1为收藏2为取消收藏
* @param {number} id - 专辑id
*/
export const likeAlbum = (t, id) => {
return axios({
method: "GET",
url: "/album/sub",
params: {
t,
id,
timestamp: new Date().getTime(),
},
});
};

View File

@@ -49,6 +49,23 @@ export const getUserPlaylist = (uid, limit = 30, offset = 0) => {
});
};
/**
* 获取用户的专辑列表
* @param {number} [limit=30] - 返回数量默认30
* @param {number} [offset=0] - 偏移数量默认0
*/
export const getUserAlbum = (limit = 30, offset = 0) => {
return axios({
method: "GET",
url: "/album/sublist",
params: {
limit,
offset,
timestamp: new Date().getTime(),
},
});
};
/**
* 获取用户收藏的歌手列表
*/

View File

@@ -88,6 +88,7 @@
<script setup>
import { PlayOne, Headset } from "@icon-park/vue-next";
import { delPlayList, likePlaylist } from "@/api/playlist";
import { likeAlbum } from "@/api/album";
import { musicStore, userStore } from "@/store";
import { useRouter } from "vue-router";
import AllArtists from "./AllArtists.vue";
@@ -163,31 +164,51 @@ const openRightMenu = (e, data) => {
},
},
{
key: "like",
key: "likePlaylist",
label: isLikeOrDislike(data.id) ? "收藏歌单" : "取消收藏歌单",
show:
user.userLogin &&
user.getUserPlayLists.has &&
props.listType === "playList" &&
router.currentRoute.value.name != "playlists"
? true
: false,
props: {
onClick: () => {
toLikePlaylist(data.id);
toChangeLike(data.id);
},
},
},
{
key: "likeAlbum",
label: isLikeOrDislike(data.id) ? "收藏专辑" : "取消收藏专辑",
show:
user.userLogin && user.getUserAlbum.has && props.listType === "album"
? true
: false,
props: {
onClick: () => {
toChangeLike(data.id);
},
},
},
{
key: "copy",
label: "复制歌单链接",
label: `复制${props.listType === "playList" ? "歌单" : "专辑"}链接`,
props: {
onClick: () => {
if (navigator.clipboard) {
try {
navigator.clipboard.writeText(
`https://music.163.com/#/playlist?id=${data.id}`
`https://music.163.com/#/${
props.listType === "playList" ? "playlist" : "album"
}?id=${data.id}`
);
$message.success(
`${
props.listType === "playList" ? "歌单" : "专辑"
}链接复制成功`
);
$message.success("歌单链接复制成功");
} catch (err) {
$message.error("复制失败:", err);
}
@@ -211,7 +232,7 @@ const onClickoutside = () => {
// 链接跳转
const toLink = (id) => {
if (props.listType == "playList" || props.listType == "topList") {
if (props.listType === "playList" || props.listType === "topList") {
router.push({
path: "/playlist",
query: {
@@ -219,7 +240,7 @@ const toLink = (id) => {
page: 1,
},
});
} else if (props.listType == "album") {
} else if (props.listType === "album") {
router.push({
path: "/album",
query: {
@@ -250,36 +271,54 @@ const toDelPlayList = (data) => {
// 判断收藏还是取消
const isLikeOrDislike = (id) => {
if (user.getUserPlayLists.like[0]) {
const index = user.getUserPlayLists.like.findIndex(
(item) => item.id === id
);
if (index !== -1) {
return false;
const listType = props.listType;
const playlists = user.getUserPlayLists.like;
const albums = user.getUserAlbum.list;
if (listType === "playList" && playlists.length) {
return !playlists.some((item) => item.id === id);
}
if (listType === "album" && albums.length) {
return !albums.some((item) => item.id === id);
}
return true;
} else {
return true;
}
};
// 收藏/取消收藏歌单
const toLikePlaylist = (id) => {
// 收藏/取消收藏
const toChangeLike = async (id) => {
const listType = props.listType;
const type = isLikeOrDislike(id) ? 1 : 2;
likePlaylist(type, id).then((res) => {
const likeFn = listType === "playList" ? likePlaylist : likeAlbum;
const likeMsg = listType === "playList" ? "歌单" : "专辑";
try {
const res = await likeFn(type, id);
if (res.code === 200) {
$message.success(`歌单${type == 1 ? "收藏成功" : "取消收藏成功"}`);
user.setUserPlayLists();
$message.success(`${likeMsg}${type == 1 ? "收藏成功" : "取消收藏成功"}`);
listType === "playList" ? user.setUserPlayLists() : user.setUserAlbum();
} else {
$message.error(`歌单${type == 1 ? "收藏失败" : "取消收藏失败"}`);
$message.error(`${likeMsg}${type == 1 ? "收藏失败" : "取消收藏失败"}`);
}
} catch (err) {
$message.error(`${likeMsg}${type == 1 ? "收藏失败" : "取消收藏失败"}`);
console.error(
`${likeMsg}${type == 1 ? "收藏失败:" : "取消收藏失败:"}` + err
);
}
});
};
onMounted(() => {
if (router.currentRoute.value.name === "playlists" && !music.catList.sub)
if (router.currentRoute.value.name === "playlists" && !music.catList.sub) {
music.setCatList();
if (user.userLogin && !user.getUserPlayLists.has) user.setUserPlayLists();
}
if (
user.userLogin &&
!user.getUserPlayLists.has &&
props.listType === "playList"
) {
user.setUserPlayLists();
}
if (user.userLogin && !user.getUserAlbum.has && props.listType === "album") {
user.setUserAlbum();
}
});
</script>

View File

@@ -5,6 +5,7 @@ import {
getUserSubcount,
getUserPlaylist,
getUserArtistlist,
getUserAlbum,
} from "@/api/user";
import { formatNumber } from "@/utils/timeTools.js";
@@ -25,6 +26,11 @@ const useUserDataStore = defineStore("userData", {
own: [], // 创建歌单
like: [], // 收藏歌单
},
// 用户专辑
userAlbum: {
has: false,
list: [],
},
// 用户收藏歌手
userArtistLists: {
has: false,
@@ -53,6 +59,10 @@ const useUserDataStore = defineStore("userData", {
getUserArtistlists(state) {
return state.userArtistLists;
},
// 获取用户收藏专辑
getUserAlbum(state) {
return state.userAlbum;
},
},
actions: {
// 更改 cookie
@@ -143,9 +153,10 @@ const useUserDataStore = defineStore("userData", {
}
},
// 更改用户收藏歌手
setUserArtistLists() {
setUserArtistLists(callback) {
if (this.userLogin) {
getUserArtistlist().then((res) => {
getUserArtistlist()
.then((res) => {
if (res.data) {
this.userArtistLists = {
list: [],
@@ -159,14 +170,44 @@ const useUserDataStore = defineStore("userData", {
size: v.musicSize,
});
});
if (typeof callback === "function") {
callback();
}
} else {
$message.error("用户收藏歌手为空");
}
})
.catch((err) => {
console.error("用户收藏歌手获取失败:" + err);
$message.error("用户收藏歌手获取失败,请刷新后重试");
});
} else {
$message.error("请登录账号后使用");
}
},
// 更改用户收藏专辑
async setUserAlbum() {
if (this.userLogin) {
try {
let offset = 0;
let totalCount = null;
this.userAlbum.list = [];
while (totalCount === null || offset < totalCount) {
const { count, data } = await getUserAlbum(30, offset);
console.log(count, data);
this.userAlbum.list = this.userAlbum.list.concat(data);
totalCount = count;
offset += 30;
}
this.userAlbum.has = true;
} catch (err) {
console.error("用户收藏专辑获取失败:" + err);
$message.error("用户收藏专辑获取失败,请刷新后重试");
}
} else {
$message.error("请登录账号后使用");
}
},
},
// 开启数据持久化
persist: [

View File

@@ -71,7 +71,7 @@
</div>
</div>
<div class="title" v-else-if="!albumId">
<span class="key">未提供所需数据</span>
<span class="key">参数不完整</span>
<br />
<n-button strong secondary @click="router.go(-1)" style="margin-top: 20px">
返回上一级

View File

@@ -1,6 +1,6 @@
<template>
<div class="artist">
<div class="artistData" v-if="artistData">
<div class="artistData" v-if="artistId && artistData">
<div class="cover">
<n-avatar
round
@@ -31,6 +31,30 @@
<n-text class="desc text-hidden" @click="artistDescShow = true">
{{ artistData.desc }}
</n-text>
<n-space class="button">
<!-- <n-button type="primary" strong secondary>
<template #icon>
<n-icon :component="PlayArrowRound" />
</template>
播放热门歌曲
</n-button> -->
<n-button
:type="artistLikeBtn ? 'primary' : 'default'"
strong
secondary
@click="toLikeArtist(artistData)"
>
<template #icon>
<n-icon
:component="
artistLikeBtn ? PersonAddAlt1Round : PersonRemoveAlt1Round
"
/>
</template>
{{ artistLikeBtn ? "收藏歌手" : "取消收藏歌手" }}
</n-button>
</n-space>
<!-- 歌手介绍 -->
<n-modal
class="s-modal"
v-model:show="artistDescShow"
@@ -44,12 +68,24 @@
</n-modal>
</div>
</div>
<div class="error" v-else-if="!artistId">
<n-text>参数不完整</n-text>
<br />
<n-button
strong
secondary
@click="router.go(-1)"
style="margin-top: 20px"
>
返回上一级
</n-button>
</div>
<n-tabs
class="main-tab"
type="segment"
@update:value="tabChange"
v-model:value="tabValue"
v-if="artistId"
v-if="artistData"
>
<n-tab name="songs"> 热门单曲 </n-tab>
<n-tab name="albums"> 专辑 </n-tab>
@@ -72,14 +108,24 @@
<script setup>
import { useRouter } from "vue-router";
import { getArtistDetail } from "@/api/artist";
import { MusicNoteFilled, AlbumFilled, VideocamRound } from "@vicons/material";
import { userStore } from "@/store";
import { getArtistDetail, likeArtist } from "@/api/artist";
import {
MusicNoteFilled,
AlbumFilled,
VideocamRound,
PersonAddAlt1Round,
PersonRemoveAlt1Round,
} from "@vicons/material";
const router = useRouter();
const user = userStore();
// 歌手数据
const artistId = ref(router.currentRoute.value.query.id);
const artistData = ref(null);
const artistDescShow = ref(false);
const artistLikeBtn = ref(false);
// Tab 默认选中
const tabValue = ref(router.currentRoute.value.path.split("/")[2]);
@@ -87,9 +133,11 @@ const tabValue = ref(router.currentRoute.value.path.split("/")[2]);
// 获取歌手数据
const getArtistDetailData = (id) => {
if (id) {
getArtistDetail(id).then((res) => {
getArtistDetail(id)
.then((res) => {
console.log(res);
artistData.value = {
id: res.data.artist.id,
name: res.data.artist.name,
occupation: res.data.identify ? res.data.identify.imageDesc : null,
cover: res.data.artist.cover,
@@ -98,9 +146,16 @@ const getArtistDetailData = (id) => {
musicSize: res.data.artist.musicSize,
mvSize: res.data.artist.mvSize,
};
// 请求后回顶
if ($mainContent) $mainContent.scrollIntoView({ behavior: "smooth" });
})
.catch((err) => {
router.go(-1);
console.error("歌手信息获取失败:" + err);
$message.error("歌手信息获取失败");
});
} else {
$message.error("请提供歌手id");
$message.error("参数不完整");
}
};
@@ -116,8 +171,47 @@ const tabChange = (value) => {
});
};
// 判断收藏还是取消
const isLikeOrDislike = (id) => {
if (user.getUserArtistlists.list[0]) {
const index = user.getUserArtistlists.list.findIndex(
(item) => item.id === Number(id)
);
if (index !== -1) {
return false;
}
return true;
} else {
return true;
}
};
// 收藏/取消收藏歌手
const toLikeArtist = (data) => {
const type = isLikeOrDislike(data.id) ? 1 : 2;
likeArtist(type, data.id).then((res) => {
if (res.code === 200) {
$message.success(
`${data.name}${type == 1 ? "收藏成功" : "取消收藏成功"}`
);
user.setUserArtistLists(() => {
artistLikeBtn.value = isLikeOrDislike(artistId.value);
});
} else {
$message.error(`${data.name}${type == 1 ? "收藏失败" : "取消收藏失败"}`);
}
});
};
onMounted(() => {
getArtistDetailData(artistId.value);
artistLikeBtn.value = isLikeOrDislike(artistId.value);
if (user.userLogin && !user.getUserArtistlists.has) {
user.setUserArtistLists(() => {
console.log("执行回调", artistId.value, isLikeOrDislike(artistId.value));
artistLikeBtn.value = isLikeOrDislike(artistId.value);
});
}
});
// 监听路由参数变化
@@ -126,6 +220,7 @@ watch(
(val) => {
artistId.value = val.query.id;
tabValue.value = val.path.split("/")[2];
artistLikeBtn.value = isLikeOrDislike(artistId.value);
if (val.path.split("/")[1] == "artist") {
getArtistDetailData(artistId.value);
}
@@ -136,6 +231,15 @@ watch(
<style lang="scss" scoped>
.artist {
margin-top: 30px;
.error {
margin-top: 30px;
margin-bottom: 20px;
.n-text {
font-size: 40px;
font-weight: bold;
margin-right: 8px;
}
}
.artistData {
display: flex;
align-items: center;
@@ -167,6 +271,8 @@ watch(
}
.cover {
margin-right: 40px;
display: flex;
align-items: center;
.n-avatar {
height: 240px;
width: 240px;
@@ -179,7 +285,7 @@ watch(
.name {
font-size: 40px;
font-weight: bold;
margin-bottom: 8px;
margin-bottom: 4px;
margin-left: 2px;
}
.occupation {
@@ -209,13 +315,16 @@ watch(
}
.desc {
margin-top: 12px;
-webkit-line-clamp: 3;
-webkit-line-clamp: 2;
cursor: pointer;
transition: all 0.3s;
&:hover {
opacity: 0.8;
}
}
.button {
margin-top: 18px;
}
}
}
.content {

View File

@@ -102,7 +102,7 @@
</div>
</div>
<div class="title" v-else-if="!playListId">
<span class="key">未提供所需数据</span>
<span class="key">参数不完整</span>
<br />
<n-button strong secondary @click="router.go(-1)" style="margin-top: 20px">
返回上一级