181 lines
5.2 KiB
Vue
181 lines
5.2 KiB
Vue
<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(true)
|
|
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, oldCode) => {
|
|
// 当 code 参数发生变化时(包括从有值变为无值,或从一个值变为另一个值)
|
|
if (newCode !== oldCode) {
|
|
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-primary-50 text-primary-700 rounded-lg">
|
|
<span>当前筛选:{{ articleTypeMap[code] || code }}</span>
|
|
<button
|
|
@click="router.push('/article') "
|
|
class="text-primary-600 hover:text-primary-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-error-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-102 [--spotlight-size:188px]"
|
|
orientation="horizontal"
|
|
reverse
|
|
spotlight
|
|
spotlight-color="primary"
|
|
highlight
|
|
highlight-color="primary"
|
|
>
|
|
<!-- 默认图片占位 -->
|
|
<div class="object-cover aspect-[4/3] w-full bg-gradient-to-br from-primary-100 to-primary-200 flex items-center justify-center rounded-lg">
|
|
<UIcon name="i-heroicons-document-text" class="size-16 text-primary-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-2 flex justify-center">
|
|
<UPagination
|
|
v-model:page="page"
|
|
:total="total"
|
|
:items-per-page="pageSize"
|
|
/>
|
|
</div>
|
|
</UPageSection>
|
|
</UPage>
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
</style> |