feat(frontend): Align admin and user API integration
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="favorite-detail-page">
|
||||
<van-nav-bar :title="favoriteTitle" fixed placeholder left-arrow @click-left="router.back()" />
|
||||
|
||||
<section class="favorite-hero">
|
||||
<div>
|
||||
<h2>{{ favoriteTitle }}</h2>
|
||||
<p>{{ description }}</p>
|
||||
</div>
|
||||
<div class="count">{{ total }} 个视频</div>
|
||||
</section>
|
||||
|
||||
<van-list
|
||||
v-model:loading="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多内容了"
|
||||
@load="loadMore"
|
||||
class="favorite-list"
|
||||
>
|
||||
<div class="video-grid">
|
||||
<VideoCard v-for="video in videos" :key="video.id" :video="video" @click="goToVideo(video.id)" />
|
||||
</div>
|
||||
</van-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import VideoCard from '@/components/video/VideoCard.vue'
|
||||
import { favoriteApi } from '@/api/favorite.ts'
|
||||
import type { VideoInfo } from '@/types'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const favoriteId = computed(() => Number(route.params.id))
|
||||
const favoriteTitle = computed(() => favoriteId.value === 1 ? '默认收藏夹' : '学习资料')
|
||||
const description = computed(() => favoriteId.value === 1 ? '最近常看的优质内容' : '项目开发与知识学习整理')
|
||||
|
||||
const videos = ref<VideoInfo[]>([])
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
|
||||
const loadMore = async () => {
|
||||
if (finished.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await favoriteApi.getFavoriteVideos(favoriteId.value, {
|
||||
pageNum: page.value,
|
||||
pageSize: 12
|
||||
})
|
||||
videos.value.push(...res.records)
|
||||
total.value = res.total
|
||||
if (videos.value.length >= res.total || res.records.length < 12) finished.value = true
|
||||
page.value++
|
||||
} catch {
|
||||
finished.value = true
|
||||
showToast('加载收藏夹失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goToVideo = (id: number) => {
|
||||
router.push(`/video/${id}`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMore()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.favorite-detail-page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
|
||||
.favorite-hero {
|
||||
margin: 18px auto 12px;
|
||||
max-width: 1400px;
|
||||
padding: 24px 22px;
|
||||
border-radius: 24px;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
|
||||
h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
|
||||
.count {
|
||||
padding: 10px 16px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-list {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 8px 12px 24px;
|
||||
}
|
||||
|
||||
.video-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: 18px 16px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user