更新前端

This commit is contained in:
2026-03-29 23:45:26 +08:00
parent 7fa24a893b
commit c1d76de658
42 changed files with 615 additions and 147 deletions

View File

@@ -1,115 +1,54 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import Navbar from '@/components/Navbar.vue'
import Hero from '@/components/Hero.vue'
import PostCard from '@/components/PostCard.vue'
import Sidebar from '@/components/Sidebar.vue'
import Footer from '@/components/Footer.vue'
import type { Post } from '@/types'
// 模拟文章数据 - 后端完成后替换为真实API调用
const posts = ref<Post[]>([
{
id: '1',
title: '《原神》4.2版本前瞻:芙宁娜技能演示与剧情预测',
slug: 'genshin-4-2-preview',
content: '',
summary: '4.2版本即将到来,让我们提前了解水神芙宁娜的技能机制以及可能的剧情发展...',
cover_image: 'https://images.unsplash.com/photo-1542751371-adc38448a05e?w=800',
author: { id: '1', username: 'Miyako', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '1', name: '游戏攻略', slug: 'game', created_at: '' },
tags: [{ id: '1', name: '原神', created_at: '' }, { id: '2', name: '攻略', created_at: '' }],
view_count: 5200,
status: 'published',
created_at: '2024-03-15T10:00:00Z',
updated_at: '2024-03-15T10:00:00Z'
},
{
id: '2',
title: '2024年必追的10部春季新番推荐',
slug: 'spring-2024-anime',
content: '',
summary: '春天到了又到了补番的季节本期为大家带来2024年春季最值得期待的新番动画...',
cover_image: 'https://images.unsplash.com/photo-1535016120720-40c6874c3b1c?w=800',
author: { id: '2', username: 'Akari', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '2', name: '动漫资讯', slug: 'anime', created_at: '' },
tags: [{ id: '3', name: '新番', created_at: '' }, { id: '4', name: '推荐', created_at: '' }],
view_count: 3800,
status: 'published',
created_at: '2024-03-14T08:00:00Z',
updated_at: '2024-03-14T08:00:00Z'
},
{
id: '3',
title: '《崩坏星穹铁道》角色强度榜 - 3月版',
slug: 'honkai-star-rail-tier-list',
content: '',
summary: '版本强势角色有哪些本期强度榜为你详细分析当前版本的T0、T1角色...',
cover_image: 'https://images.unsplash.com/photo-1550745165-9bc0b252726f?w=800',
author: { id: '1', username: 'Miyako', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '1', name: '游戏攻略', slug: 'game', created_at: '' },
tags: [{ id: '2', name: '崩坏星穹铁道', created_at: '' }, { id: '5', name: '强度榜', created_at: '' }],
view_count: 2900,
status: 'published',
created_at: '2024-03-13T15:30:00Z',
updated_at: '2024-03-13T15:30:00Z'
},
{
id: '4',
title: '手办入坑指南:从萌新到进阶的全方位攻略',
slug: 'figure-beginner-guide',
content: '',
summary: '想入手第一只手办但不知道如何选择?这篇指南将带你了解手办的各种分类、选购渠道...',
cover_image: 'https://images.unsplash.com/photo-1608889175123-8ee362201f81?w=800',
author: { id: '3', username: 'Sakura', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '3', name: '二次元美图', slug: 'pictures', created_at: '' },
tags: [{ id: '6', name: '手办', created_at: '' }, { id: '7', name: '教程', created_at: '' }],
view_count: 2100,
status: 'published',
created_at: '2024-03-12T12:00:00Z',
updated_at: '2024-03-12T12:00:00Z'
},
{
id: '5',
title: '同人创作分享:用画笔描绘心中的二次元世界',
slug: 'fanart-sharing',
content: '',
summary: '本期收录了多位优秀画师的作品,让我们一起欣赏这些充满想象力的同人创作...',
cover_image: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=800',
author: { id: '2', username: 'Akari', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '4', name: '同人创作', slug: 'fanwork', created_at: '' },
tags: [{ id: '8', name: '同人', created_at: '' }, { id: '9', name: '绘画', created_at: '' }],
view_count: 1800,
status: 'published',
created_at: '2024-03-11T09:00:00Z',
updated_at: '2024-03-11T09:00:00Z'
},
{
id: '6',
title: '《约定的梦幻岛》最新话解析:剧情走向深度分析',
slug: 'neverland-analysis',
content: '',
summary: '最新一话的剧情信息量巨大,让我们来深度分析一下剧情走向和角色心理...',
cover_image: 'https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=800',
author: { id: '4', username: 'Ken', email: '', is_active: true, created_at: '', updated_at: '' },
category: { id: '2', name: '动漫资讯', slug: 'anime', created_at: '' },
tags: [{ id: '10', name: '约定的梦幻岛', created_at: '' }, { id: '11', name: '分析', created_at: '' }],
view_count: 1500,
status: 'published',
created_at: '2024-03-10T20:00:00Z',
updated_at: '2024-03-10T20:00:00Z'
}
])
const categories = [
{ name: '全部', slug: '' },
{ name: '动漫资讯', slug: 'anime' },
{ name: '游戏攻略', slug: 'game' },
{ name: '二次元美图', slug: 'pictures' },
{ name: '同人创作', slug: 'fanwork' },
]
import { postApi } from '@/api/post'
import { categoryApi } from '@/api/category'
import type { Post, Category } from '@/types'
const posts = ref<Post[]>([])
const categories = ref<Category[]>([{ id: '', name: '全部', slug: '', created_at: '' }])
const selectedCategory = ref('')
const loading = ref(false)
async function fetchPosts(categoryId?: string) {
loading.value = true
try {
const params: any = { page: 1, page_size: 20 }
if (categoryId) {
params.category_id = categoryId
}
const response = await postApi.getList(params)
posts.value = response.data.items.filter(p => p.status === 'published')
} catch (error) {
console.error('Failed to fetch posts:', error)
} finally {
loading.value = false
}
}
async function fetchCategories() {
try {
const response = await categoryApi.getAll()
categories.value = [{ id: '', name: '全部', slug: '', created_at: '' }, ...response.data]
} catch (error) {
console.error('Failed to fetch categories:', error)
}
}
function handleCategoryChange(slug: string) {
selectedCategory.value = slug
const catId = slug ? categories.value.find(c => c.slug === slug)?.id : ''
fetchPosts(catId)
}
onMounted(() => {
fetchCategories()
fetchPosts()
})
</script>
<template>
@@ -123,8 +62,8 @@ const selectedCategory = ref('')
<div class="category-buttons">
<button
v-for="cat in categories"
:key="cat.slug"
@click="selectedCategory = cat.slug"
:key="cat.id"
@click="handleCategoryChange(cat.slug)"
class="category-btn"
:class="{ active: selectedCategory === cat.slug }"
>
@@ -138,7 +77,9 @@ const selectedCategory = ref('')
<!-- 文章列表 -->
<section class="posts-section">
<h2 class="section-title">最新文章</h2>
<div class="posts-grid">
<div v-if="loading" class="text-center py-8 text-gray-500">加载中...</div>
<div v-else-if="posts.length === 0" class="text-center py-8 text-gray-500">暂无文章</div>
<div v-else class="posts-grid">
<PostCard v-for="post in posts" :key="post.id" :post="post" />
</div>
</section>