2021-09-30 13:44:23 +08:00
|
|
|
|
<script lang="ts" setup>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
import { computed, ref } from 'vue';
|
2024-05-22 12:07:48 +08:00
|
|
|
|
import { onBeforeRouteUpdate, useRouter } from 'vue-router';
|
2024-05-16 18:54:30 +08:00
|
|
|
|
import { useStore } from 'vuex';
|
|
|
|
|
|
|
|
|
|
|
|
import { getListDetail } from '@/api/list';
|
|
|
|
|
|
import { getUserDetail, getUserPlaylist, getUserRecord } from '@/api/user';
|
|
|
|
|
|
import PlayBottom from '@/components/common/PlayBottom.vue';
|
|
|
|
|
|
import SongItem from '@/components/common/SongItem.vue';
|
|
|
|
|
|
import MusicList from '@/components/MusicList.vue';
|
2023-12-21 11:26:51 +08:00
|
|
|
|
import type { Playlist } from '@/type/listDetail';
|
2024-05-16 18:54:30 +08:00
|
|
|
|
import type { IUserDetail } from '@/type/user';
|
|
|
|
|
|
import { getImgUrl, setAnimationClass, setAnimationDelay } from '@/utils';
|
2021-10-25 15:56:26 +08:00
|
|
|
|
|
2024-05-22 12:07:48 +08:00
|
|
|
|
defineOptions({
|
|
|
|
|
|
name: 'User',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
|
const store = useStore();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const userDetail = ref<IUserDetail>();
|
|
|
|
|
|
const playList = ref<any[]>([]);
|
|
|
|
|
|
const recordList = ref();
|
2024-05-22 15:14:26 +08:00
|
|
|
|
|
|
|
|
|
|
const user = computed(() => store.state.user);
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
|
|
|
|
|
const loadPage = async () => {
|
2024-05-22 15:14:26 +08:00
|
|
|
|
if (!user.value) {
|
2024-05-16 18:54:30 +08:00
|
|
|
|
router.push('/login');
|
|
|
|
|
|
return;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 15:14:26 +08:00
|
|
|
|
const { data: userData } = await getUserDetail(user.value.userId);
|
2024-05-16 18:54:30 +08:00
|
|
|
|
userDetail.value = userData;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
2024-05-22 15:14:26 +08:00
|
|
|
|
const { data: playlistData } = await getUserPlaylist(user.value.userId);
|
2024-05-16 18:54:30 +08:00
|
|
|
|
playList.value = playlistData.playlist;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
2024-05-22 15:14:26 +08:00
|
|
|
|
const { data: recordData } = await getUserRecord(user.value.userId);
|
2024-05-16 18:54:30 +08:00
|
|
|
|
recordList.value = recordData.allData;
|
|
|
|
|
|
};
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
2024-05-22 15:14:26 +08:00
|
|
|
|
onActivated(() => {
|
|
|
|
|
|
if (!user.value) {
|
|
|
|
|
|
router.push('/login');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
loadPage();
|
|
|
|
|
|
}
|
2024-05-16 18:54:30 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const isShowList = ref(false);
|
|
|
|
|
|
const list = ref<Playlist>();
|
2021-10-25 15:56:26 +08:00
|
|
|
|
// 展示歌单
|
|
|
|
|
|
const showPlaylist = async (id: number) => {
|
2024-05-16 18:54:30 +08:00
|
|
|
|
const { data } = await getListDetail(id);
|
|
|
|
|
|
isShowList.value = true;
|
|
|
|
|
|
list.value = data.playlist;
|
|
|
|
|
|
};
|
2021-10-25 15:56:26 +08:00
|
|
|
|
|
|
|
|
|
|
// 格式化歌曲列表项
|
|
|
|
|
|
const formatDetail = computed(() => (detail: any) => {
|
2024-05-16 18:54:30 +08:00
|
|
|
|
const song = {
|
2021-10-25 15:56:26 +08:00
|
|
|
|
artists: detail.ar,
|
|
|
|
|
|
name: detail.al.name,
|
|
|
|
|
|
id: detail.al.id,
|
2024-05-16 18:54:30 +08:00
|
|
|
|
};
|
2021-10-25 15:56:26 +08:00
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
|
detail.song = song;
|
|
|
|
|
|
detail.picUrl = detail.al.picUrl;
|
|
|
|
|
|
return detail;
|
|
|
|
|
|
});
|
2023-12-11 16:22:05 +08:00
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
|
const handlePlay = () => {
|
|
|
|
|
|
const tracks = recordList.value || [];
|
|
|
|
|
|
store.commit('setPlayList', tracks);
|
|
|
|
|
|
};
|
2021-09-30 13:44:23 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
2021-10-25 15:56:26 +08:00
|
|
|
|
<div class="user-page" @click.stop="isShowList = false">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-if="userDetail"
|
2024-05-16 18:54:30 +08:00
|
|
|
|
class="left"
|
2021-10-25 15:56:26 +08:00
|
|
|
|
:class="setAnimationClass('animate__fadeInLeft')"
|
2023-12-19 14:45:12 +08:00
|
|
|
|
:style="{ backgroundImage: `url(${getImgUrl(user.backgroundUrl)})` }"
|
2021-10-25 15:56:26 +08:00
|
|
|
|
>
|
2021-09-30 13:44:23 +08:00
|
|
|
|
<div class="page">
|
|
|
|
|
|
<div class="user-name">{{ user.nickname }}</div>
|
|
|
|
|
|
<div class="user-info">
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<n-avatar round :size="50" :src="getImgUrl(user.avatarUrl, '50y50')" />
|
2021-09-30 13:44:23 +08:00
|
|
|
|
<div class="user-info-list">
|
|
|
|
|
|
<div class="user-info-item">
|
|
|
|
|
|
<div class="label">{{ userDetail.profile.followeds }}</div>
|
|
|
|
|
|
<div>粉丝</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="user-info-item">
|
|
|
|
|
|
<div class="label">{{ userDetail.profile.follows }}</div>
|
|
|
|
|
|
<div>关注</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="user-info-item">
|
|
|
|
|
|
<div class="label">{{ userDetail.level }}</div>
|
|
|
|
|
|
<div>等级</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="uesr-signature">{{ userDetail.profile.signature }}</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="play-list" :class="setAnimationClass('animate__fadeInLeft')">
|
2024-05-22 12:07:48 +08:00
|
|
|
|
<div class=" ">创建的歌单</div>
|
2023-12-21 16:45:06 +08:00
|
|
|
|
<n-scrollbar>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<div v-for="(item, index) in playList" :key="index" class="play-list-item" @click="showPlaylist(item.id)">
|
|
|
|
|
|
<n-image :src="getImgUrl(item.coverImgUrl, '50y50')" class="play-list-item-img" lazy preview-disabled />
|
2023-12-21 16:45:06 +08:00
|
|
|
|
<div class="play-list-item-info">
|
|
|
|
|
|
<div class="play-list-item-name">{{ item.name }}</div>
|
|
|
|
|
|
<div class="play-list-item-count">{{ item.trackCount }}首,播放{{ item.playCount }}次</div>
|
|
|
|
|
|
</div>
|
2021-09-30 13:44:23 +08:00
|
|
|
|
</div>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<play-bottom />
|
2023-12-21 16:45:06 +08:00
|
|
|
|
</n-scrollbar>
|
2021-09-30 13:44:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2021-10-25 15:56:26 +08:00
|
|
|
|
<div class="right" :class="setAnimationClass('animate__fadeInRight')">
|
2023-12-21 16:45:06 +08:00
|
|
|
|
<div class="title">听歌排行</div>
|
|
|
|
|
|
<div class="record-list">
|
|
|
|
|
|
<n-scrollbar>
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(item, index) in recordList"
|
|
|
|
|
|
:key="item.song.id"
|
2024-05-16 18:54:30 +08:00
|
|
|
|
class="record-item"
|
2023-12-21 16:45:06 +08:00
|
|
|
|
:class="setAnimationClass('animate__bounceInUp')"
|
|
|
|
|
|
:style="setAnimationDelay(index, 50)"
|
|
|
|
|
|
>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<song-item class="song-item" :item="formatDetail(item.song)" @play="handlePlay" />
|
2023-12-21 16:45:06 +08:00
|
|
|
|
<div class="play-count">{{ item.playCount }}次</div>
|
|
|
|
|
|
</div>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<play-bottom />
|
2023-12-21 16:45:06 +08:00
|
|
|
|
</n-scrollbar>
|
|
|
|
|
|
</div>
|
2021-10-25 15:56:26 +08:00
|
|
|
|
</div>
|
2024-05-16 18:54:30 +08:00
|
|
|
|
<music-list v-if="list" v-model:show="isShowList" :name="list.name" :song-list="list.tracks" />
|
2021-09-30 13:44:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.user-page {
|
2023-12-21 11:26:51 +08:00
|
|
|
|
@apply flex h-full;
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.left {
|
|
|
|
|
|
max-width: 600px;
|
|
|
|
|
|
background-color: #0d0d0d;
|
|
|
|
|
|
background-size: 100%;
|
2023-12-21 16:45:06 +08:00
|
|
|
|
@apply flex-1 rounded-2xl overflow-hidden relative bg-no-repeat h-full;
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.page {
|
2023-12-21 16:45:06 +08:00
|
|
|
|
@apply p-4 w-full z-10 flex flex-col h-full;
|
2021-10-25 15:56:26 +08:00
|
|
|
|
background-color: #0d0d0d66;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-name {
|
|
|
|
|
|
@apply text-xl text-white font-bold opacity-70 mb-4;
|
|
|
|
|
|
}
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.uesr-signature {
|
|
|
|
|
|
@apply text-white opacity-70 mt-4;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-info {
|
|
|
|
|
|
@apply flex items-center;
|
|
|
|
|
|
&-list {
|
|
|
|
|
|
@apply flex justify-around w-2/5 text-center opacity-70;
|
|
|
|
|
|
.label {
|
|
|
|
|
|
@apply text-xl text-white font-bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-09-30 13:44:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.right {
|
2024-05-22 12:07:48 +08:00
|
|
|
|
@apply flex-1 ml-4 overflow-hidden h-full;
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.record-list {
|
|
|
|
|
|
background-color: #0d0d0d;
|
2024-05-22 12:07:48 +08:00
|
|
|
|
@apply rounded-2xl;
|
|
|
|
|
|
height: calc(100% - 3.75rem);
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.record-item {
|
|
|
|
|
|
@apply flex items-center px-4;
|
|
|
|
|
|
}
|
2021-09-30 13:44:23 +08:00
|
|
|
|
|
2021-10-25 15:56:26 +08:00
|
|
|
|
.song-item {
|
|
|
|
|
|
@apply flex-1;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
}
|
2021-10-25 15:56:26 +08:00
|
|
|
|
|
|
|
|
|
|
.play-count {
|
|
|
|
|
|
@apply text-white opacity-70 ml-4;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.title {
|
|
|
|
|
|
@apply text-xl text-white font-bold opacity-70 m-4;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.play-list {
|
2023-12-21 16:45:06 +08:00
|
|
|
|
@apply mt-4 py-4 px-2 rounded-xl flex-1 overflow-hidden;
|
2021-09-30 13:44:23 +08:00
|
|
|
|
background-color: #000000;
|
|
|
|
|
|
&-title {
|
|
|
|
|
|
@apply text-lg text-white opacity-70;
|
|
|
|
|
|
}
|
|
|
|
|
|
&-item {
|
|
|
|
|
|
@apply flex items-center hover:bg-gray-800 transition-all duration-200 px-2 py-1 rounded-xl cursor-pointer;
|
|
|
|
|
|
&-img {
|
|
|
|
|
|
width: 60px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
@apply rounded-xl;
|
|
|
|
|
|
}
|
|
|
|
|
|
&-info {
|
|
|
|
|
|
@apply ml-2;
|
|
|
|
|
|
}
|
|
|
|
|
|
&-name {
|
|
|
|
|
|
@apply text-white;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-05-16 18:54:30 +08:00
|
|
|
|
</style>
|