feat(frontend): Align admin and user API integration

This commit is contained in:
2026-04-18 18:21:31 +08:00
parent 3adb088eca
commit 2247d235ec
74 changed files with 8626 additions and 647 deletions
@@ -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>