基础的文章列表功能
This commit is contained in:
parent
efb6a8c222
commit
61b129631d
|
|
@ -134,8 +134,16 @@ onMounted(() => {
|
|||
class="wow fadeInDown animated active mb-8 lg:mb-12">
|
||||
|
||||
<!-- 分类标题 -->
|
||||
<div :title="category.name" class="text-xl lg:text-2xl text-blue-600 text-center cursor-pointer mb-5">
|
||||
{{ category.name }}
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div :title="category.name" class="text-xl lg:text-2xl text-blue-600">
|
||||
{{ category.name }}
|
||||
</div>
|
||||
<a
|
||||
:href="`/article?code=${category.code}`"
|
||||
class="text-sm text-blue-600 hover:text-blue-800 hover:underline transition-colors"
|
||||
>
|
||||
查看更多
|
||||
</a>
|
||||
</div>
|
||||
<hr class="border-gray-300 mb-5"/>
|
||||
<div class="py-5"/>
|
||||
|
|
@ -169,6 +177,16 @@ onMounted(() => {
|
|||
<div class="text-gray-600 text-lg">暂无新闻数据</div>
|
||||
<div class="py-12"/>
|
||||
</div>
|
||||
|
||||
<!-- 查看全部链接 -->
|
||||
<div v-if="!loading && !error && newsData.length > 0" class="text-center mt-8 mb-4">
|
||||
<a
|
||||
href="/article"
|
||||
class="inline-block px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white text-base font-medium rounded-lg transition-all duration-150 ease-in-out no-underline hover:shadow-lg"
|
||||
>
|
||||
查看全部文章
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
176
app/pages/article/index.vue
Normal file
176
app/pages/article/index.vue
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { getArticleList, type Article } from '~/config/api'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// 从查询参数获取分类代码
|
||||
const code = computed(() => route.query.code as string | undefined)
|
||||
|
||||
// 响应式数据
|
||||
const articles = ref<Article[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(5)
|
||||
const total = ref(0)
|
||||
|
||||
// 文章类型映射(用于显示中文名称)
|
||||
const articleTypeMap: Record<string, string> = {
|
||||
solution: '解决方案',
|
||||
developKnowledge: '开发知识',
|
||||
industryTrend: '行业动态'
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
const formatDate = (timeString: string): string => {
|
||||
if (!timeString) return ''
|
||||
const date = new Date(timeString)
|
||||
if (isNaN(date.getTime())) return timeString
|
||||
const Y = date.getFullYear()
|
||||
const M = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const D = String(date.getDate()).padStart(2, '0')
|
||||
return `${Y}.${M}.${D}`
|
||||
}
|
||||
|
||||
// 获取文章列表
|
||||
const fetchArticles = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
const response = await getArticleList({
|
||||
pageNum: page.value,
|
||||
pageSize: pageSize.value,
|
||||
code: code.value
|
||||
})
|
||||
|
||||
articles.value = response.rows || []
|
||||
total.value = response.total || 0
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '获取文章列表失败'
|
||||
console.error('获取文章列表时发生错误:', err)
|
||||
articles.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 监听分页变化
|
||||
watch(page, () => {
|
||||
fetchArticles()
|
||||
// 滚动到顶部
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
})
|
||||
|
||||
// 监听查询参数变化
|
||||
watch(() => route.query.code, (newCode) => {
|
||||
if (newCode !== code.value) {
|
||||
page.value = 1
|
||||
fetchArticles()
|
||||
}
|
||||
}, { immediate: false })
|
||||
|
||||
onMounted(() => {
|
||||
fetchArticles()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UPage>
|
||||
<img alt="" src="https://api.ccttiot.com/image-1762162779566.png">
|
||||
<UPageSection
|
||||
:ui="{
|
||||
container:'lg:px-0 lg:pt-10'
|
||||
}">
|
||||
<!-- 筛选提示 -->
|
||||
<div v-if="code" class="mb-6 px-4">
|
||||
<div class="inline-flex items-center gap-2 px-4 py-2 bg-blue-50 text-blue-700 rounded-lg">
|
||||
<span>当前筛选:{{ articleTypeMap[code] || code }}</span>
|
||||
<button
|
||||
@click="router.push('/article')"
|
||||
class="text-blue-600 hover:text-blue-800 underline text-sm"
|
||||
>
|
||||
清除筛选
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="text-center py-20">
|
||||
<div class="text-gray-600 text-lg animate-pulse">正在加载文章...</div>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="error" class="text-center py-20">
|
||||
<div class="text-red-600 text-lg mb-6">{{ error }}</div>
|
||||
<UButton @click="fetchArticles" color="primary">
|
||||
重新加载
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- 文章列表 -->
|
||||
<div v-else-if="articles.length > 0" class="space-y-6">
|
||||
<UPageCard
|
||||
v-for="article in articles"
|
||||
:key="article.id"
|
||||
:description="article.brief || ''"
|
||||
:title="article.title"
|
||||
:to="`/article/${article.id}`"
|
||||
:ui="{
|
||||
root:'group',
|
||||
container: 'relative grid lg:grid-cols-[1fr_4fr] gap-8 p-6',
|
||||
}"
|
||||
class="hover:shadow-2xl hover:scale-105 hover:translate-x-8"
|
||||
orientation="horizontal"
|
||||
reverse
|
||||
spotlight
|
||||
spotlight-color="primary"
|
||||
>
|
||||
<!-- 默认图片占位 -->
|
||||
<div class="object-cover aspect-[4/3] w-full bg-gradient-to-br from-blue-100 to-blue-200 flex items-center justify-center rounded-lg">
|
||||
<UIcon name="i-heroicons-document-text" class="size-16 text-blue-400" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<UButton
|
||||
class="px-0 gap-0 text-right"
|
||||
label="去阅读"
|
||||
size="xl"
|
||||
variant="link"
|
||||
>
|
||||
<template #trailing>
|
||||
<UIcon
|
||||
class="size-4 text-primary transition-all opacity-0 group-hover:translate-x-1 group-hover:opacity-100"
|
||||
name="i-lucide-arrow-right"
|
||||
/>
|
||||
</template>
|
||||
</UButton>
|
||||
</template>
|
||||
<template #header>
|
||||
<div class="text-left text-gray-600">{{ formatDate(article.createTime) }}</div>
|
||||
</template>
|
||||
</UPageCard>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-else class="text-center py-20">
|
||||
<div class="text-gray-600 text-lg">暂无文章</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div v-if="!loading && !error && total > 0" class="mt-8 flex justify-center">
|
||||
<UPagination
|
||||
v-model:page="page"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
/>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</UPage>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user