feat(AlbumDetail): 实现专辑详情页面的数据展示和布局

添加了专辑详情页面的数据获取逻辑和布局,包括专辑封面、名称、艺术家、简介和曲目列表的展示。同时,更新了路由参数和 API 请求路径,以支持专辑详情的动态加载。
This commit is contained in:
Astrian Zheng 2025-05-24 15:15:47 +10:00
parent b73748c084
commit e415c1ef42
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
5 changed files with 73 additions and 7 deletions

View File

@ -9,7 +9,7 @@ const route = useRoute()
<template>
<div class="w-screen h-screen overflow-hidden bg-[#191919]">
<div class="flex flex-col w-full h-full overflow-y-auto pb-24">
<div class="py-8 px-4 sticky top-0 bg-gradient-to-b from-[#00000080] to-transparent">
<div class="py-8 px-4 md:px-8 sticky top-0 bg-gradient-to-b from-[#00000080] to-transparent z-10">
<div class="flex justify-between align-center" v-if="(() => {
if (route.path === '/lucky' || route.path === '/library' || route.path === '/') { return true }
else { return false }

View File

@ -29,8 +29,14 @@ export default {
async getAlbum(cid: string) {
const album: {
data: ApiResponse
} = await msrInstance.get(`album/${cid}/data`)
} = await msrInstance.get(`album/${cid}/detail`)
if (album.data.code!== 0) { throw new Error(`Cannot get album: ${album.data.msg}`) }
return album.data.data as Album
const albumMeta: {
data: ApiResponse
} = await msrInstance.get(`album/${cid}/data`)
let data = album.data.data as Album
data.artistes = (albumMeta.data.data as Album).artistes
console.log(albumMeta)
return data
}
}

View File

@ -7,7 +7,7 @@ import AlbumDetailView from './pages/AlbumDetail.vue'
const routes = [
{ path: '/', component: HomePage },
{ path: '/albums/:id', component: AlbumDetailView },
{ path: '/albums/:albumId', component: AlbumDetailView },
]
const router = createRouter({

View File

@ -1,3 +1,62 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import apis from '../apis'
import { useRoute } from 'vue-router'
const album = ref<Album>()
const route = useRoute()
const albumId = route.params.albumId
onMounted(async () => {
try {
const res = await apis.getAlbum(albumId as string)
album.value = res
console.log(res)
} catch (error) {
console.log(error)
}
})
function artistsOrganize(list: string[]) {
if (list.length === 0) { return '未知音乐人' }
return list.map((artist) => {
return artist
}).join(' / ')
}
</script>
<template>
<div>album</div>
<div class="px-4 md:px-8 flex gap-8">
<div class="mx-auto w-48 md:mx-0 md:w-72">
<div class="sticky top-[6.625rem] flex flex-col gap-8">
<div class="border border-[#5b5b5b] rounded-md overflow-hidden shadow-2xl bg-neutral-800 sticky">
<img :src="album?.coverUrl" class="md:w-72 md:h-72 w-48 h-48 object-contain" />
</div>
<div class="flex flex-col gap-2">
<div class="text-white text-2xl font-semibold">{{ album?.name }}</div>
<div class="text-sky-200 text-xl">{{ artistsOrganize(album?.artistes ?? []) }}</div>
<div class="text-white/50 text-sm">{{ album?.intro }}</div>
</div>
</div>
</div>
<div class="flex-1 flex flex-col gap-8">
<div class="flex flex-col gap-2">
<button v-for="(track, index) in album?.songs" :key="track.cid" class="flex align-center gap-4 text-left odd:bg-neutral-800/20 px-2 py-1 rounded-md hover:bg-neutral-800">
<div class="w-8 flex justify-center items-center">
<span class="text-2xl text-white">{{ index + 1 }}</span>
</div>
<div>
<div class="text-white text-base">{{ track.name }}</div>
<div class="text-white/50 text-sm">{{ artistsOrganize(track.artistes) }}</div>
</div>
</button>
</div>
<div v-if="album?.songs?.length" class="text-white/50 text-base mb-4">
{{ album?.songs?.length }} 首曲目
</div>
</div>
</div>
</template>

5
src/vite-env.d.ts vendored
View File

@ -7,12 +7,12 @@ type SongList = {
type Song = {
cid: string
name: string
albumCid: string
albumCid?: string
sourceUrl?: string
lyricUrl?: string | null
mvUrl?: string | null
mvCoverUrl?: string | null
artists: string[]
artistes: string[]
}
type Album = {
@ -23,6 +23,7 @@ type Album = {
coverUrl: string
coverDeUrl?: string
artistes: string[]
songs?: Song[]
}
type AlbumList = Album[]