Files
nl-blogs/client/src/templates/magazine/pages/Blog.vue
2026-08-24 13:06:04 +08:00

86 lines
2.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div class="mag-toolbar">
<input v-model="keyword" class="mag-input" placeholder="搜索文章…" @keyup.enter="load(1)" />
<button class="mag-btn" @click="load(1)">搜索</button>
<select v-model="selectedCat" class="mag-input" @change="load(1)">
<option :value="0">全部分类</option>
<option v-for="c in categories" :key="c.id" :value="c.id">{{ c.name }}</option>
</select>
</div>
<div v-if="loading" style="padding:40px 0;color:var(--m-muted);">排版中</div>
<template v-else>
<div class="mag-grid">
<router-link v-for="(p, i) in posts" :key="p.id" :to="`/blog/${p.id}`" class="mag-article" :data-index="String(i + 1).padStart(2, '0')">
<div class="mag-article-cat">{{ p.categoryName || '未分类' }}</div>
<h2 class="mag-article-title">{{ p.title }}</h2>
<p class="mag-article-excerpt">{{ p.excerpt || '(暂无摘要)' }}</p>
<div class="mag-article-meta">{{ p.date }}</div>
</router-link>
</div>
<div v-if="!posts.length" style="padding:40px 0;color:var(--m-muted);">暂无文章</div>
<div v-if="totalPages > 1" class="mag-pager">
<button class="mag-btn" :disabled="page <= 1" @click="load(page - 1)"> 上一页</button>
<span style="font-size:13px;color:var(--m-muted);align-self:center;">{{ page }} / {{ totalPages }}</span>
<button class="mag-btn" :disabled="page >= totalPages" @click="load(page + 1)">下一页 </button>
</div>
</template>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { fetchPosts, fetchCategories, type Post } from '../../../services/api'
const posts = ref<Post[]>([])
const categories = ref<Awaited<ReturnType<typeof fetchCategories>>>([])
const keyword = ref('')
const selectedCat = ref(0)
const page = ref(1)
const totalPages = ref(1)
const loading = ref(true)
const PAGE_SIZE = 10
const load = async (p: number) => {
loading.value = true
const res = await fetchPosts(keyword.value || undefined, selectedCat.value > 0 ? selectedCat.value : undefined, undefined, undefined, p, PAGE_SIZE)
const list = 'list' in res ? res.list : (Array.isArray(res) ? res : [])
const total = 'total' in res ? res.total : list.length
posts.value = list
totalPages.value = Math.max(1, Math.ceil(total / PAGE_SIZE))
page.value = p
loading.value = false
}
onMounted(async () => {
categories.value = await fetchCategories()
await load(1)
})
</script>
<style scoped>
.mag-toolbar {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 30px;
border-bottom: 2px solid var(--m-ink);
padding-bottom: 18px;
}
.mag-pager {
display: flex;
gap: 16px;
justify-content: center;
margin-top: 34px;
}
.mag-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
</style>