xlqx/app/pages/article-xlqx/index.vue
2025-11-18 10:04:12 +08:00

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>