Files
hjc-web/app/templates/template-07/pages/CaseList.vue
T
weicw-dshsa 09dfded0c8 style: 文章/案例列表改为纯文字竖向列表
去掉封面图卡片网格,改为单列分隔线列表:
- 文章行:日期 | 标题 | 栏目
- 案例行:日期 | 标题,下方摘要与客户

顺带清理去掉图片后已无引用的 fileUrl 解构,
并为案例列表补上空状态(此前空数据渲染为空白)。
2026-09-29 02:49:56 +08:00

136 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="min-h-screen py-16 bg-gray-50">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-12">
<h1 class="text-3xl font-bold text-gray-900 mb-4">{{ pageTitle }}</h1>
<p class="text-gray-600 max-w-2xl mx-auto">展示我们的成功案例与行业经验</p>
</div>
<div v-if="pending" class="flex justify-center py-12">
<SiteLoading />
</div>
<SiteError v-else-if="error" message="获取案例列表失败" />
<div v-else-if="cases.length > 0" class="max-w-[1200px] mx-auto bg-white rounded-xl shadow-sm px-6 py-2">
<ul class="divide-y divide-gray-100">
<li v-for="item in cases" :key="item.id">
<NuxtLink :to="`/case/${item.id}`" class="block py-4 group">
<div class="flex items-baseline gap-4">
<span class="shrink-0 text-xs text-gray-400 tabular-nums">
{{ formatDate(item.projectTime || item.createTime) }}
</span>
<h2 class="flex-1 min-w-0 text-base text-gray-900 truncate group-hover:text-blue-600 transition-colors">
{{ item.title }}
</h2>
</div>
<div class="mt-1 pl-[5.5rem]">
<p v-if="stripHtml(item.summary)" class="text-sm text-gray-500 line-clamp-1">
{{ stripHtml(item.summary) }}
</p>
<div v-if="item.clientName" class="mt-1 text-xs text-gray-400">
客户:{{ item.clientName }}
</div>
</div>
</NuxtLink>
</li>
</ul>
</div>
<!-- 空状态 -->
<div v-else class="text-center py-20">
<p class="text-gray-500">暂无案例内容</p>
</div>
<!-- 分页 -->
<div v-if="totalPages > 1" class="flex justify-center mt-12">
<nav class="flex items-center gap-2">
<button
v-for="p in totalPages"
:key="p"
class="px-4 py-2 text-sm rounded-lg transition-colors"
:class="p === currentPage ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-blue-50'"
@click="currentPage = p"
>
{{ p }}
</button>
</nav>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs'
import type { CaseItem, PageResult } from '~/types'
import { collectDescendantNavIds } from '~/utils/nav-tree'
/**
* 模板 1 - 案例列表页
*/
const route = useRoute()
const { allNavigations, fetchSiteInfo } = useSite()
// 确保导航数据已加载(用于栏目标题与分类判定)
await fetchSiteInfo()
// 列表(栏目)入口 /case/{navigationId} 时按分类过滤;/case 根目录展示全部案例
const navigationId = computed<number | undefined>(() => {
const id = route.params.id
return id ? Number(id) : undefined
})
// 聚合:父栏目访问时递归收集自身 + 所有后代栏目 navigationId,交给后端 IN 查询
const categoryIds = computed<string | undefined>(() => {
const ids = collectDescendantNavIds(navigationId.value, allNavigations.value || [])
return ids.length ? ids.join(',') : undefined
})
const currentPage = ref(1)
const limit = 12
const { data, pending, error } = await useFetch<PageResult<CaseItem>>('/api/case/list', {
key: `case-list-${categoryIds.value ?? navigationId.value ?? 'all'}-p${currentPage.value}`,
query: {
page: currentPage,
limit,
...(categoryIds.value
? { categoryIds: categoryIds.value }
: (navigationId.value ? { navigationId: navigationId.value } : {}))
},
watch: [currentPage, categoryIds, navigationId]
})
const cases = computed(() => data.value?.list || [])
const totalCount = computed(() => data.value?.count ?? 0)
const totalPages = computed(() => Math.max(1, Math.ceil(totalCount.value / limit)))
// 切换栏目时回到第 1 页
watch([categoryIds, navigationId], () => {
currentPage.value = 1
})
// 栏目标题:命中导航取导航标题,否则用模块默认名
const pageTitle = computed(() => {
const id = navigationId.value
if (id == null) return '案例展示'
const navs = (allNavigations.value || []) as any[]
const find = (items: any[]): any => {
for (const it of items) {
if (it.navigationId === id) return it
if (it.children?.length) {
const f = find(it.children)
if (f) return f
}
}
return undefined
}
return find(navs)?.title || '案例展示'
})
function formatDate(date?: string) {
if (!date) return ''
return dayjs(date).format('YYYY-MM-DD')
}
</script>