ufutx-pc-website/src/views/News/News.vue
2025-07-24 18:26:24 +08:00

527 lines
12 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="page-container">
<!-- 已有Banner组件 -->
<BannerCarousel />
<!-- 核心内容区 -->
<div class="news-content">
<!-- 标签切换动态加载 -->
<el-tabs v-model="activeTab" class="news-tabs" @tab-change="resetPage">
<el-tab-pane v-for="item in categories" :key="item.name" :label="item.name" :name="item.name">
<template #label>
<div class="categories-label">{{ item.name }}</div>
</template>
</el-tab-pane>
</el-tabs>
<!-- 新闻列表(数据加载后显示) -->
<div v-if="!loading && newsData.length > 0" class="news-list">
<div v-for="(item, idx) in filteredNews" :key="idx" class="news-item">
<img :src="item.pic" alt="image" class="news-cover" />
<div class="news-info">
<h3 class="news-title">{{ item.title }}</h3>
<h3 class="news-label">{{ item.publisher }}</h3>
<div class="news-wrap" @click="openArticleInNewWindow(item.id)">
<div class="view-btn">查看详情</div>
<div class="news-date">
<img
class="icon"
src="https://images.health.ufutx.com/202506/13/c5e3552a870fd254610290bbabce5e30.png"
/>
<p>{{ item.create_time }}</p>
</div>
</div>
</div>
</div>
</div>
<!-- 无数据时显示占位图(加载完成且数据为空) -->
<div v-else-if="!loading && newsData.length === 0" class="empty-state">
<img
src="https://images.health.ufutx.com/202507/02/259f20509b57b36199ef7619f8d63733.png"
alt="暂无数据"
class="empty-img"
/>
<p class="empty-text">暂无内容</p>
</div>
<!-- 加载状态 -->
<div v-else class="loading-container">
<!-- <el-spinner size="large"></el-spinner>-->
<p>加载中...</p>
</div>
<!-- 分页 -->
<div class="pagination-wrap">
<el-pagination
:current-page="currentPage"
:page-sizes="[10, 20, 50]"
:page-size="pageSize"
background
layout="total,prev, pager, next"
:total="totalCount"
@size-change="handleSizeChange"
@current-change="handlePageChange"
>
</el-pagination>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import BannerCarousel from '@/views/News/sections/BannerCarousel.vue'
import request from '@/utils/request' // 假设已有请求工具函数
// 路由相关
// import { useRoute, useRouter } from 'vue-router'
import { openNewWindow } from '@/utils/navigation.ts'
// const route = useRoute()
// const router = useRouter()
// 响应式数据
const activeTab = ref('') // 激活标签
const currentPage = ref(1) // 当前页码
const pageSize = ref(15) // 每页条数
const totalCount = ref(0) // 总数据量
const loading = ref(false) // 加载状态
const categories = ref<Array<any>>([]) // 标签分类
const newsData = ref<Array<any>>([]) // 新闻数据
// 计算当前显示的新闻(带分页)
const filteredNews = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
return newsData.value.slice(start, start + pageSize.value)
})
// 跳转详情页携带文章ID
const openArticleInNewWindow = (id: number) => {
openNewWindow(`/articleDetail/${id}`)
}
// 获取标签分类列表
const fetchCategories = async () => {
loading.value = true
try {
// 从接口获取标签分类(:plat从路由参数获取
const res = await request.get(`/go/api/:plat/v1/article/category/list`)
if (res.data.length > 0) {
categories.value = res.data || []
// 设置默认激活标签(如果有数据)
if (categories.value.length > 0) {
activeTab.value = categories.value[0].name
}
} else {
// ElMessage.error(res.message || '获取分类失败')
}
} catch (error: any) {
console.error('获取分类列表失败', error)
ElMessage.error('网络错误,请稍后重试')
} finally {
loading.value = false
}
}
// 获取新闻列表数据
const fetchNewsList = async (category_id: string, page: number) => {
loading.value = true
try {
// 接口参数type根据标签分类传递
const params = {
category_id: category_id,
page
}
// 调用新闻列表接口
const res = await request.get(`/go/api/:plat/v1/article/list`, params)
if (res.code === 0) {
newsData.value = res.data.data || []
console.log(newsData.value)
totalCount.value = res.data.total_count || 0
} else {
ElMessage.error(res.message || '获取新闻失败')
}
} catch (error: any) {
console.error('获取新闻列表失败', error)
ElMessage.error('网络错误,请稍后重试')
} finally {
loading.value = false
}
}
// 标签切换时重置页码并加载数据
const resetPage = () => {
currentPage.value = 1
if (activeTab.value) {
loadNewsData()
}
}
// 加载新闻数据(整合标签和分页参数)
const loadNewsData = () => {
if (!activeTab.value) return
// 假设标签分类的name对应新闻接口的type参数
console.log(activeTab.value)
const category = categories.value.find(item => item.name === activeTab.value)
if (category) {
fetchNewsList(category.id || '', currentPage.value)
}
}
// 分页事件
const handleSizeChange = (val: number) => {
pageSize.value = val
currentPage.value = 1
loadNewsData()
}
const handlePageChange = (val: number) => {
currentPage.value = val
loadNewsData()
}
// 组件挂载时加载分类和新闻数据
onMounted(async () => {
await fetchCategories()
if (activeTab.value) {
loadNewsData()
}
})
// 监听标签切换,重新加载数据
// watch(activeTab, () => {
// loadNewsData()
// })
</script>
<style scoped lang="less">
@import '@/styles/global.less';
.page-container {
min-height: 100vh;
background-color: @bg-color;
}
.news-content {
max-width: 1920px;
padding: 0 20px;
}
/* 加载状态样式 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
color: @text-color-secondary;
.el-spinner {
margin-bottom: 20px;
}
}
/* 标签切换样式还原设计的蓝色下划线 */
.news-tabs {
padding-top: 50px;
.categories-label {
font-size: 32px;
}
:deep(.el-tabs__nav-wrap) {
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100vw;
height: 0.5px;
background-color: #b5b5b5;
z-index: var(--el-index-normal);
}
}
:deep(.el-tabs__active-bar) {
background-color: @primary-dark; // 下划线颜色
height: 3px;
bottom: -20px !important;
margin-top: 20px;
}
:deep(.el-tabs__header) {
margin: 0;
width: 100%;
.el-tabs__nav {
justify-content: center;
width: 100%;
margin-bottom: 20px;
.el-tabs__item {
font-size: @font-size-xxl;
color: @text-color-secondary;
margin-right: 104px;
&.is-active {
color: @primary-dark; // 激活态文字颜色
}
}
}
}
// 响应式适配
@media (max-width: @tablet-breakpoint) {
.categories-label {
font-size: @font-size-lg;
}
:deep(.el-tabs__item) {
margin-right: @space-md;
font-size: @font-size-lg;
}
:deep(.el-tabs__active-bar) {
bottom: -15px !important;
}
}
@media (max-width: @mobile-breakpoint) {
:deep(.el-tabs__item) {
margin-right: @space-sm;
font-size: @font-size-md;
}
:deep(.el-tabs__active-bar) {
bottom: -10px !important;
}
}
}
/* 新闻列表 */
.news-list {
display: flex;
flex-direction: column;
gap: 50px;
padding: 100px 192px 0;
.news-item {
display: flex;
align-items: center;
border-bottom: 0.3px solid #b5b5b5;
padding-bottom: 50px;
.news-cover {
width: 500px;
height: 260px;
object-fit: cover;
border-radius: @border-radius-md;
flex-shrink: 0; /* 禁止收缩保证宽度不变 */
margin-right: 30px;
}
.news-info {
width: 100%;
padding-top: 20px;
text-align: left;
.news-title {
font-size: @font-size-lg;
font-weight: @font-weight-medium;
color: @text-color;
margin-bottom: @space-sm;
}
.news-label {
font-size: @font-size-sm;
color: @text-color-secondary;
margin-top: 13px;
margin-bottom: 76px;
}
.news-wrap {
display: flex;
justify-content: space-between;
.view-btn {
padding: 6px 16px;
color: @primary-dark;
border-radius: 4px;
border: 1px solid var(--1060-ff, #1060ff);
cursor: pointer;
}
.news-date {
font-size: @font-size-sm;
color: @text-color-secondary;
display: flex;
align-items: center;
gap: 8px;
.icon {
width: 18px;
height: 18px;
object-fit: contain;
}
}
}
}
}
// 响应式适配
@media (max-width: @tablet-breakpoint) {
padding: @space-xl @space-md 0;
.news-item {
flex-direction: column;
align-items: flex-start;
gap: @space-lg;
.news-cover {
width: 100%;
height: auto;
margin-right: 0;
margin-bottom: @space-lg;
}
.news-info .news-wrap {
flex-direction: column;
gap: @space-sm;
.view-btn {
align-self: flex-start;
}
.news-date {
order: -1;
}
}
}
}
@media (max-width: @mobile-breakpoint) {
padding: @space-lg @space-md 0;
gap: @space-xl;
.news-item {
padding-bottom: @space-lg;
.news-cover {
height: 180px;
}
.news-info .news-title {
font-size: @font-size-md;
}
.news-info .news-label {
font-size: @font-size-sm;
}
.news-info .view-btn {
font-size: @font-size-xs;
}
}
.news-date {
.icon {
width: 40px;
height: 40px;
}
p {
font-size: @font-size-xs;
}
}
}
}
/* 分页样式 */
.pagination-wrap {
margin-top: 50px;
padding-bottom: 170px;
display: flex;
justify-content: center;
:deep(.el-pager li.is-active) {
color: @primary-dark;
}
.el-pagination {
.el-pagination__total {
color: @text-color-light;
}
.el-pager li.active {
background-color: @primary-color;
color: #fff;
}
.el-pagination__sizes {
margin: 0 @space-md;
}
}
// 响应式适配
@media (max-width: @mobile-breakpoint) {
.el-pagination {
.el-pagination__total {
font-size: @font-size-xs;
}
.el-pager li {
width: 28px;
height: 28px;
line-height: 28px;
font-size: @font-size-xs;
}
.el-pagination__sizes {
margin: 0 @space-xs;
.el-input {
font-size: @font-size-xs;
}
}
}
}
}
// 无数据占位图样式
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100px 0; // 与列表区域上下间距保持一致
text-align: center;
.empty-img {
width: 300px; // 调整占位图宽度根据实际图片比例
height: auto;
margin-bottom: 20px;
opacity: 0.8; // 轻微降低透明度避免过于突兀
}
.empty-text {
font-size: 20px;
color: @text-color-secondary;
.mt(10px);
}
// 响应式适配
@media (max-width: @mobile-breakpoint) {
.empty-img {
width: 200px; // 移动端缩小图片
}
.empty-text {
font-size: @font-size-md;
}
}
}
.pagination {
margin-top: 20px;
text-align: right;
}
:deep(.el-pager li.is-active) {
background-color: #1665fc !important;
color: #ffffff !important;
}
</style>