feat: 添加每日推荐 样式, 请求等大量优化

This commit is contained in:
alger
2024-05-22 12:07:48 +08:00
parent c6f1e0b233
commit 32b39c7927
23 changed files with 409 additions and 103 deletions
+5 -1
View File
@@ -27,6 +27,10 @@
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
import { setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'History',
});
const { delMusic, musicList } = useMusicHistory();
</script>
@@ -38,7 +42,7 @@ const { delMusic, musicList } = useMusicHistory();
}
.history-list-content {
@apply px-4 mt-2;
@apply px-4 mt-2 pb-28;
.history-item {
@apply flex items-center justify-between;
&-content {
+17 -12
View File
@@ -1,16 +1,18 @@
<template>
<div class="main-page">
<!-- 推荐歌手 -->
<recommend-singer />
<div class="main-content">
<!-- 歌单分类列表 -->
<playlist-type />
<!-- 本周最热音乐 -->
<recommend-songlist />
<!-- 推荐最新专辑 -->
<recommend-album />
<n-scrollbar :size="100">
<div class="main-page">
<!-- 推荐歌手 -->
<recommend-singer />
<div class="main-content">
<!-- 歌单分类列表 -->
<playlist-type />
<!-- 本周最热音乐 -->
<recommend-songlist />
<!-- 推荐最新专辑 -->
<recommend-album />
</div>
</div>
</div>
</n-scrollbar>
</template>
<script lang="ts" setup>
@@ -18,6 +20,9 @@ const RecommendSinger = defineAsyncComponent(() => import('@/components/Recommen
const PlaylistType = defineAsyncComponent(() => import('@/components/PlaylistType.vue'));
const RecommendSonglist = defineAsyncComponent(() => import('@/components/RecommendSonglist.vue'));
const RecommendAlbum = defineAsyncComponent(() => import('@/components/RecommendAlbum.vue'));
defineOptions({
name: 'Home',
});
</script>
<style lang="scss" scoped>
@@ -25,6 +30,6 @@ const RecommendAlbum = defineAsyncComponent(() => import('@/components/Recommend
@apply h-full w-full;
}
.main-content {
@apply mt-6 flex pb-28;
@apply mt-6 flex mb-28;
}
</style>
+4 -2
View File
@@ -2,12 +2,15 @@
import { useRoute } from 'vue-router';
import { getListByCat, getListDetail, getRecommendList } from '@/api/list';
import PlayBottom from '@/components/common/PlayBottom.vue';
import MusicList from '@/components/MusicList.vue';
import type { IRecommendItem } from '@/type/list';
import type { IListDetail } from '@/type/listDetail';
import { formatNumber, getImgUrl, setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'List',
});
const recommendList = ref();
const showMusic = ref(false);
@@ -82,7 +85,6 @@ watch(
<div class="recommend-item-title">{{ item.name }}</div>
</div>
</div>
<play-bottom />
</n-scrollbar>
<music-list
v-if="listDetail?.playlist"
+43 -23
View File
@@ -4,9 +4,13 @@ import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { checkQr, createQr, getLoginStatus, getQrKey, getUserDetail, loginByCellphone } from '@/api/login';
import { checkQr, createQr, getQrKey, getUserDetail, loginByCellphone } from '@/api/login';
import { setAnimationClass } from '@/utils';
defineOptions({
name: 'Login',
});
const message = useMessage();
const store = useStore();
const router = useRouter();
@@ -16,37 +20,53 @@ onMounted(() => {
loadLogin();
});
const timerRef = ref(null);
const loadLogin = async () => {
const qrKey = await getQrKey();
const key = qrKey.data.data.unikey;
const { data } = await createQr(key);
qrUrl.value = data.data.qrimg;
timerIsQr(key);
try {
const qrKey = await getQrKey();
const key = qrKey.data.data.unikey;
const { data } = await createQr(key);
qrUrl.value = data.data.qrimg;
const timer = timerIsQr(key);
// 添加对定时器的引用,以便在出现错误时可以清除
timerRef.value = timer as any;
} catch (error) {
console.error('加载登录信息时出错:', error);
}
};
// 使用 ref 来保存定时器,便于在任何地方清除它
const timerIsQr = (key: string) => {
const timer = setInterval(async () => {
const { data } = await checkQr(key);
try {
const { data } = await checkQr(key);
if (data.code === 800) {
clearInterval(timer);
}
if (data.code === 803) {
// 将token存入localStorage
localStorage.setItem('token', data.cookie);
const user = await getUserDetail();
store.state.user = user.data.profile;
message.success('登录成功');
if (data.code === 800) {
clearInterval(timer);
timerRef.value = null;
}
if (data.code === 803) {
localStorage.setItem('token', data.cookie);
const user = await getUserDetail();
store.state.user = user.data.profile;
message.success('登录成功');
await getLoginStatus().then((res) => {
console.log(res);
});
clearInterval(timer);
setTimeout(() => {
clearInterval(timer);
timerRef.value = null;
router.push('/user');
}, 1000);
}
} catch (error) {
console.error('检查二维码状态时出错:', error);
// 在出现错误时清除定时器
clearInterval(timer);
timerRef.value = null;
}
}, 5000);
}, 2000);
return timer;
};
// 是否扫码登陆
+5 -1
View File
@@ -48,6 +48,10 @@
<script setup lang="ts">
import { useIpcRenderer } from '@vueuse/electron';
defineOptions({
name: 'Lyric',
});
const ipcRenderer = useIpcRenderer();
const lyricData = ref({
@@ -74,7 +78,7 @@ const lyricSetting = ref({
? JSON.parse(localStorage.getItem('lyricData') || '')
: {
isTop: false,
theme: 'light',
theme: 'dark',
isLock: false,
}),
});
+5 -1
View File
@@ -53,6 +53,10 @@ import { getMvUrl, getTopMv } from '@/api/mv';
import { IMvItem } from '@/type/mv';
import { formatNumber, getImgUrl, setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'Mv',
});
const showMv = ref(false);
const mvList = ref<Array<IMvItem>>([]);
const playMvItem = ref<IMvItem>();
@@ -91,7 +95,7 @@ const close = () => {
}
&-content {
@apply grid gap-6 pb-4 mt-2;
@apply grid gap-6 pb-28 mt-2;
grid-template-columns: repeat(auto-fill, minmax(14%, 1fr));
}
+33 -22
View File
@@ -19,30 +19,32 @@
<!-- 搜索到的歌曲列表 -->
<n-layout class="search-list" :class="setAnimationClass('animate__fadeInUp')" :native-scrollbar="false">
<div class="title">{{ hotKeyword }}</div>
<div class="search-list-box">
<template v-if="searchDetail">
<div
v-for="(item, index) in searchDetail?.songs"
:key="item.id"
:class="setAnimationClass('animate__bounceInRight')"
:style="setAnimationDelay(index, 50)"
>
<song-item :item="item" @play="handlePlay" />
</div>
<template v-for="(list, key) in searchDetail">
<template v-if="key.toString() !== 'songs'">
<div
v-for="(item, index) in list"
:key="item.id"
:class="setAnimationClass('animate__bounceInRight')"
:style="setAnimationDelay(index, 50)"
>
<SearchItem :item="item" />
</div>
<n-spin :show="searchDetailLoading">
<div class="search-list-box">
<template v-if="searchDetail">
<div
v-for="(item, index) in searchDetail?.songs"
:key="item.id"
:class="setAnimationClass('animate__bounceInRight')"
:style="setAnimationDelay(index, 50)"
>
<song-item :item="item" @play="handlePlay" />
</div>
<template v-for="(list, key) in searchDetail">
<template v-if="key.toString() !== 'songs'">
<div
v-for="(item, index) in list"
:key="item.id"
:class="setAnimationClass('animate__bounceInRight')"
:style="setAnimationDelay(index, 50)"
>
<SearchItem :item="item" />
</div>
</template>
</template>
</template>
</template>
</div>
</div>
</n-spin>
</n-layout>
</div>
</template>
@@ -59,10 +61,15 @@ import SongItem from '@/components/common/SongItem.vue';
import type { IHotSearch } from '@/type/search';
import { setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'Search',
});
const route = useRoute();
const router = useRouter();
const searchDetail = ref<any>();
const searchType = ref(Number(route.query.type) || 1);
const searchDetailLoading = ref(false);
// 热搜列表
const hotSearchData = ref<IHotSearch>();
@@ -93,6 +100,8 @@ const loadSearch = async (keywords: any) => {
hotKeyword.value = keywords;
searchDetail.value = undefined;
if (!keywords) return;
searchDetailLoading.value = true;
const { data } = await getSearch({ keywords, type: searchType.value });
const songs = data.result.songs || [];
@@ -111,6 +120,8 @@ const loadSearch = async (keywords: any) => {
songs,
albums,
};
searchDetailLoading.value = false;
};
loadSearch(route.query.keyword);
+4
View File
@@ -34,6 +34,10 @@ import { useRouter } from 'vue-router';
import store from '@/store';
defineOptions({
name: 'Setting',
});
const setData = ref(store.state.setData);
const router = useRouter();
+10 -5
View File
@@ -1,6 +1,6 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { onBeforeRouteUpdate, useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { getListDetail } from '@/api/list';
@@ -12,6 +12,10 @@ import type { Playlist } from '@/type/listDetail';
import type { IUserDetail } from '@/type/user';
import { getImgUrl, setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'User',
});
const store = useStore();
const router = useRouter();
const userDetail = ref<IUserDetail>();
@@ -35,7 +39,7 @@ const loadPage = async () => {
recordList.value = recordData.allData;
};
watchEffect(() => {
onMounted(() => {
const localUser = localStorage.getItem('user');
store.state.user = localUser ? JSON.parse(localUser) : null;
user = store.state.user;
@@ -100,7 +104,7 @@ const handlePlay = () => {
<div class="uesr-signature">{{ userDetail.profile.signature }}</div>
<div class="play-list" :class="setAnimationClass('animate__fadeInLeft')">
<div class="play-list-title">创建的歌单</div>
<div class=" ">创建的歌单</div>
<n-scrollbar>
<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 />
@@ -167,10 +171,11 @@ const handlePlay = () => {
}
.right {
@apply flex-1 ml-4;
@apply flex-1 ml-4 overflow-hidden h-full;
.record-list {
background-color: #0d0d0d;
@apply rounded-2xl h-full;
@apply rounded-2xl;
height: calc(100% - 3.75rem);
.record-item {
@apply flex items-center px-4;
}