添加文章列表接口

This commit is contained in:
WindowBird 2025-10-31 16:27:10 +08:00
parent 1cc7c965cc
commit 22f8d99a2a
3 changed files with 264 additions and 0 deletions

View File

@ -0,0 +1,177 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { getArticleList, type Article } from '~/config/api'
//
interface NewsCategory {
name: string
code: string
articleList: Article[]
}
//
const newsData = ref<NewsCategory[]>([])
const loading = ref(false)
const error = ref('')
//
const articleTypes = [
{ name: '解决方案', code: 'solution' },
{ name: '开发知识', code: 'developKnowledge' },
{ name: '行业动态', code: 'industryTrend' }
]
//
const formatTime = (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')
const h = String(date.getHours()).padStart(2, '0')
const m = String(date.getMinutes()).padStart(2, '0')
return `${Y}-${M}-${D} ${h}:${m}`
}
//
const getArticleLink = (articleId: string): string => {
return `/article/${articleId}`
}
// 2
const getDisplayArticles = (articles: Article[]): Article[] => {
return articles.slice(0, 2)
}
//
const fetchNewsData = async (): Promise<void> => {
loading.value = true
error.value = ''
try {
//
const promises = articleTypes.map(async (type) => {
try {
const response = await getArticleList({
code: type.code,
pageNum: 1,
pageSize: 10
})
return {
name: type.name,
code: type.code,
articleList: response.rows || []
}
} catch (err) {
console.error(`获取 ${type.name} 文章失败:`, err)
return {
name: type.name,
code: type.code,
articleList: []
}
}
})
const results = await Promise.all(promises)
newsData.value = results
} catch (err) {
error.value = err instanceof Error ? err.message : '获取新闻数据失败'
console.error('获取新闻数据时发生错误:', err)
} finally {
loading.value = false
}
}
onMounted(() => {
fetchNewsData()
})
</script>
<template>
<!--box3 新闻-->
<div class="container mx-auto px-4">
<!-- 标题区域 -->
<div class="text-center py-12">
<div
class="text-black text-4xl leading-tight mb-10 wow fadeInDown animated"
style="visibility: visible; animation-name: fadeInDown;">
开发资讯
</div>
<div class="text-gray-600 text-lg wow fadeInUp animated" style="visibility: visible; animation-name: fadeInUp;">
NEWS
</div>
<div class="py-5"/>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="text-center py-12">
<div class="text-gray-600 text-lg animate-pulse">正在加载新闻...</div>
<div class="py-12"/>
</div>
<!-- 错误状态 -->
<div v-else-if="error" class="text-center py-12">
<div class="text-red-600 text-lg mb-5">加载失败: {{ error }}</div>
<button
class="inline-block px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-base font-normal rounded transition-all duration-150 ease-in-out cursor-pointer border border-transparent"
@click="fetchNewsData">
重新加载
</button>
<div class="py-12"/>
</div>
<!-- 新闻分类列表 -->
<div v-else class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
<div
v-for="(category, index) in newsData"
:key="category.name"
:data-wow-delay="`${300 + index * 200}ms`"
:style="`visibility: visible; animation-delay: ${300 + index * 200}ms; animation-name: fadeInDown;`"
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>
<hr class="border-gray-300 mb-5"/>
<div class="py-5"/>
<!-- 文章列表 -->
<template v-if="category.articleList.length > 0">
<ul class="list-none p-0 m-0">
<li v-for="article in getDisplayArticles(category.articleList)" :key="article.id" class="mb-2.5">
<a
:href="getArticleLink(article.id)"
:title="article.title"
class="text-gray-600 text-sm block py-1.5 no-underline hover:underline transition-all"
target="_blank">
<div class="flex items-center justify-between gap-3">
<span class="truncate flex-1 pr-2">{{ article.title }}</span>
<span class="text-gray-500 text-xs whitespace-nowrap flex-shrink-0">{{ formatTime(article.createTime) }}</span>
</div>
<div class="py-5"/>
</a>
</li>
</ul>
</template>
<div v-else class="text-center text-gray-600 text-sm py-5">
暂无文章
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!loading && !error && newsData.length === 0" class="text-center py-12">
<div class="text-gray-600 text-lg">暂无新闻数据</div>
<div class="py-12"/>
</div>
</div>
</template>

View File

@ -35,6 +35,43 @@ export interface ApiResponse<T> {
data: T
}
/**
*
*/
export interface Article {
id: string
title: string
brief: string | null
content: string | null
createTime: string
createBy?: string | null
updateTime?: string | null
updateBy?: string | null
remark?: string | null
code?: string | null
status?: string | null
scope?: string | null
deleted?: string | null
areaPermissions?: string | null
}
/**
*
*/
export interface PageResponse<T> {
total: number
rows: T[]
}
/**
*
*/
export interface GetArticleListParams {
pageNum?: number
pageSize?: number
code?: string
}
/**
*
* @returns Promise<BannerItem[]>
@ -72,3 +109,52 @@ export async function getBannerList(): Promise<BannerItem[]> {
}
}
/**
*
* @param params pageNum, pageSize, code等
* @returns Promise<PageResponse<Article>>
*/
export async function getArticleList(
params: GetArticleListParams = {}
): Promise<PageResponse<Article>> {
try {
const { pageNum = 1, pageSize = 10, code } = params
// 构建查询参数
const queryParams: Record<string, string> = {
pageNum: pageNum.toString(),
pageSize: pageSize.toString(),
}
if (code) {
queryParams.code = code
}
const response = await $fetch<PageResponse<Article>>(
`${API_BASE_URL}/app/owArticle/list`,
{
method: 'GET',
params: queryParams,
headers: {
'Content-Type': 'application/json',
},
}
)
// 检查响应数据
if (response && Array.isArray(response.rows)) {
return {
total: response.total || 0,
rows: response.rows || [],
}
}
console.warn('获取文章列表失败,返回空数据', response)
return { total: 0, rows: [] }
} catch (error) {
console.error('获取文章列表时发生错误:', error)
// 发生错误时返回空数据,避免页面崩溃
return { total: 0, rows: [] }
}
}

View File

@ -2,6 +2,7 @@
<div>
<AppHeader/>
<slot/>
<DevelopNews/>
<AppFooter/>
<ContactFloatingButton/>
</div>