Files
template-nuxt4/app/pages/expert/index.vue
2026-04-29 01:33:33 +08:00

214 lines
4.3 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="expert-page">
<div class="page-header">
<h1 class="page-title">专家资讯</h1>
<p class="page-desc">汇聚各领域权威专家提供专业视角与研究成果</p>
</div>
<!-- 分类标签 -->
<div class="category-tabs">
<a-radio-group v-model:value="activeType" button-style="solid" @change="handleTypeChange">
<a-radio-button value="">全部</a-radio-button>
<a-radio-button value="view">专家视点</a-radio-button>
<a-radio-button value="dynamic">专家动态</a-radio-button>
</a-radio-group>
</div>
<!-- 专家/文章列表 -->
<div class="expert-list">
<div v-for="item in items" :key="item.id" class="expert-item" @click="handleView(item)">
<div v-if="item.avatar" class="expert-avatar">
<img :alt="item.expertName" :src="item.avatar" />
</div>
<div v-else class="expert-default-avatar">{{ item.expertName?.charAt(0) }}</div>
<div class="expert-content">
<h3 class="expert-title">{{ item.title }}</h3>
<div class="expert-meta">
<span class="meta-item">{{ item.expertName }}</span>
<span class="meta-item">{{ item.expertTitle }}</span>
<span class="meta-item">{{ item.publishTime }}</span>
</div>
<p class="expert-overview">{{ item.overview }}</p>
</div>
</div>
<div v-if="loading" class="loading-placeholder">
<a-spin size="large" />
</div>
<div v-if="!loading && items.length === 0" class="empty-placeholder">
<a-empty description="暂无内容" />
</div>
</div>
<!-- 分页 -->
<div v-if="total > pageSize" class="pagination-wrap">
<a-pagination
v-model:current="currentPage"
:page-size="pageSize"
:total="total"
@change="handlePageChange"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { message } from 'ant-design-vue'
useHead({ title: '专家资讯 - 决策咨询网' })
const router = useRouter()
const activeType = ref((useRoute().query.type as string) || '')
const currentPage = ref(1)
const pageSize = ref(12)
const total = ref(0)
const loading = ref(false)
const items = ref<any[]>([])
async function loadItems() {
loading.value = true
try {
// TODO: 接入实际API
} catch (e: any) {
message.error('加载失败')
} finally {
loading.value = false
}
}
function handleTypeChange() {
currentPage.value = 1
loadItems()
}
function handlePageChange(page: number) {
currentPage.value = page
loadItems()
}
function handleView(item: any) {
router.push(`/expert/${item.id}`)
}
onMounted(() => {
loadItems()
})
</script>
<style scoped>
.expert-page {
max-width: 1200px;
margin: 0 auto;
padding: 40px 20px;
}
.page-header {
text-align: center;
margin-bottom: 40px;
}
.page-title {
font-size: 32px;
font-weight: 700;
color: #1f2937;
margin: 0 0 12px;
}
.page-desc {
font-size: 16px;
color: #6b7280;
margin: 0;
}
.category-tabs {
margin-bottom: 32px;
text-align: center;
}
.expert-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.expert-item {
display: flex;
gap: 20px;
padding: 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
cursor: pointer;
transition: all 0.2s;
}
.expert-item:hover {
box-shadow: 0 4px 16px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.expert-avatar,
.expert-default-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
flex-shrink: 0;
overflow: hidden;
}
.expert-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.expert-default-avatar {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
font-size: 32px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
}
.expert-content {
flex: 1;
}
.expert-title {
font-size: 18px;
font-weight: 600;
color: #1f2937;
margin: 0 0 8px;
}
.expert-meta {
display: flex;
gap: 12px;
font-size: 12px;
color: #6b7280;
margin-bottom: 8px;
}
.expert-overview {
font-size: 14px;
color: #6b7280;
margin: 0;
line-height: 1.6;
}
.loading-placeholder,
.empty-placeholder {
padding: 60px 0;
text-align: center;
}
.pagination-wrap {
margin-top: 40px;
text-align: center;
}
</style>