feat(home): 更新首页新闻栏目数据获取逻辑
- 将硬编码的新闻栏目数据替换为从CMS动态获取 - 添加了新闻栏目数据类型定义和解析函数 - 实现了新闻文章链接生成和标题解析功能 - 更新了页面参数传递,将navigationId改为categoryId - 添加了加载状态和空数据状态的UI显示 - 集成了文章详情页的动态路由跳转功能
This commit is contained in:
@@ -215,7 +215,7 @@ const {
|
||||
async () => {
|
||||
if (!isValidNavigationId.value) return null
|
||||
return await pageCmsArticle({
|
||||
navigationId: navigationId.value,
|
||||
categoryId: navigationId.value,
|
||||
page: page.value,
|
||||
limit: limit.value,
|
||||
keywords: keywords.value || undefined
|
||||
|
||||
@@ -26,22 +26,30 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-6 grid grid-cols-12 gap-6">
|
||||
<div v-for="c in columns" :key="c.title" class="col-span-12 lg:col-span-4">
|
||||
<div v-for="c in columns" :key="c.key" class="col-span-12 lg:col-span-4">
|
||||
<div class="panel">
|
||||
<div class="column-head">
|
||||
<div class="column-title">{{ c.title }}</div>
|
||||
<a href="#" class="column-more" @click.prevent>更多 +</a>
|
||||
<NuxtLink v-if="c.moreTo" :to="c.moreTo" class="column-more">更多 +</NuxtLink>
|
||||
<span v-else class="column-more opacity-60">更多 +</span>
|
||||
</div>
|
||||
<div class="column-list">
|
||||
<a
|
||||
v-for="it in c.items"
|
||||
:key="it"
|
||||
class="column-item"
|
||||
href="#"
|
||||
@click.prevent
|
||||
>
|
||||
{{ it }}
|
||||
</a>
|
||||
<template v-if="newsPending">
|
||||
<div class="column-empty">加载中...</div>
|
||||
</template>
|
||||
<template v-else-if="!c.items.length">
|
||||
<div class="column-empty">暂无文章</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NuxtLink
|
||||
v-for="(it, idx) in c.items"
|
||||
:key="String(it.articleId ?? it.code ?? `${c.key}-${idx}`)"
|
||||
class="column-item"
|
||||
:to="resolveArticleLink(it, c.navId)"
|
||||
>
|
||||
{{ resolveArticleTitle(it) }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,6 +91,10 @@ import { usePageSeo } from '@/composables/usePageSeo'
|
||||
import { getAdByCode } from '@/api/cms/cmsAd'
|
||||
import type { CmsAd } from '@/api/cms/cmsAd/model'
|
||||
import { COMPANY } from '@/config/company'
|
||||
import { listCmsNavigation } from '@/api/cms/cmsNavigation'
|
||||
import type { CmsNavigation } from '@/api/cms/cmsNavigation/model'
|
||||
import { pageCmsArticle } from '@/api/cms/cmsArticle'
|
||||
import type { CmsArticle } from '@/api/cms/cmsArticle/model'
|
||||
|
||||
usePageSeo({
|
||||
title: '首页',
|
||||
@@ -163,38 +175,78 @@ const services = [
|
||||
}
|
||||
]
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '公司动态',
|
||||
items: [
|
||||
'桂乐淘官方网站上线公告',
|
||||
'业务范围与资质信息已更新',
|
||||
'合作咨询:欢迎留言,我们将尽快联系',
|
||||
'合规提示:涉及许可项目以许可文件为准',
|
||||
'更多动态敬请期待...'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '行业资讯',
|
||||
items: [
|
||||
'生物基材料与绿色低碳趋势速览',
|
||||
'食品流通与预包装食品合规要点',
|
||||
'冷链与生鲜品质管理建议',
|
||||
'更多资讯敬请期待...',
|
||||
'更多资讯敬请期待...'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '合规与公告',
|
||||
items: [
|
||||
'一般项目:凭营业执照依法自主开展经营活动',
|
||||
'许可项目:依法须经批准的项目,经批准后方可开展',
|
||||
'具体经营项目以相关部门批准文件或许可证件为准',
|
||||
'更多公告敬请期待...',
|
||||
'更多公告敬请期待...'
|
||||
]
|
||||
const NEWS_PARENT_ID = 4548
|
||||
|
||||
type HomeNewsColumn = {
|
||||
key: string
|
||||
navId?: number
|
||||
title: string
|
||||
moreTo: string | null
|
||||
items: CmsArticle[]
|
||||
}
|
||||
|
||||
function resolveNavTitle(nav: CmsNavigation) {
|
||||
return String(nav.title || nav.label || nav.code || '').trim()
|
||||
}
|
||||
|
||||
function resolveArticleTitle(a: CmsArticle) {
|
||||
return String(a.title || a.code || '未命名文章').trim()
|
||||
}
|
||||
|
||||
function resolveArticleLink(a: CmsArticle, navId?: number) {
|
||||
const articleId = typeof a.articleId === 'number' && Number.isFinite(a.articleId) ? a.articleId : NaN
|
||||
const code = String(a.code || '').trim()
|
||||
return {
|
||||
path: '/article-item',
|
||||
query: {
|
||||
id: Number.isFinite(articleId) ? String(articleId) : undefined,
|
||||
code: !Number.isFinite(articleId) && code ? code : undefined,
|
||||
navId: typeof navId === 'number' && Number.isFinite(navId) ? String(navId) : undefined
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const { data: newsRaw, pending: newsPending } = await useAsyncData<HomeNewsColumn[]>(
|
||||
`home-news-${NEWS_PARENT_ID}`,
|
||||
async () => {
|
||||
const navs = await listCmsNavigation({ parentId: NEWS_PARENT_ID }).catch(() => [])
|
||||
const top3 = [...navs]
|
||||
.filter((it) => typeof it?.navigationId === 'number')
|
||||
.sort((a, b) => (a.sortNumber ?? 0) - (b.sortNumber ?? 0))
|
||||
.slice(0, 3)
|
||||
|
||||
const bundles = await Promise.all(
|
||||
top3.map(async (nav) => {
|
||||
const navId = nav.navigationId
|
||||
const title = resolveNavTitle(nav) || (typeof navId === 'number' ? `栏目 ${navId}` : '栏目')
|
||||
const page = typeof navId === 'number'
|
||||
? await pageCmsArticle({ categoryId: navId, page: 1, limit: 10 }).catch(() => null)
|
||||
: null
|
||||
|
||||
return {
|
||||
key: String(navId ?? title),
|
||||
navId,
|
||||
title,
|
||||
moreTo: typeof navId === 'number' ? `/article/${navId}` : null,
|
||||
items: page?.list ?? []
|
||||
} satisfies HomeNewsColumn
|
||||
})
|
||||
)
|
||||
|
||||
return bundles
|
||||
}
|
||||
)
|
||||
|
||||
const columns = computed<HomeNewsColumn[]>(() => {
|
||||
if (newsRaw.value?.length) return newsRaw.value
|
||||
if (!newsPending.value) return []
|
||||
// Keep layout stable while SSR/client is loading.
|
||||
return [
|
||||
{ key: 'news-loading-1', navId: undefined, title: '加载中', moreTo: null, items: [] },
|
||||
{ key: 'news-loading-2', navId: undefined, title: '加载中', moreTo: null, items: [] },
|
||||
{ key: 'news-loading-3', navId: undefined, title: '加载中', moreTo: null, items: [] }
|
||||
]
|
||||
})
|
||||
|
||||
const compliance = [
|
||||
{
|
||||
@@ -393,6 +445,12 @@ function scrollToCompany() {
|
||||
padding: 10px 14px 14px;
|
||||
}
|
||||
|
||||
.column-empty {
|
||||
padding: 12px 0;
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.column-item {
|
||||
display: block;
|
||||
padding: 8px 0;
|
||||
|
||||
Reference in New Issue
Block a user