NewsDetail.vue 4.74 KB
<template>
  <div class="page-container">
    <!-- Loading状态 -->
    <div class="loading-container" v-if="isLoading">
      <van-loading size="24px" color="#8b4513">加载中...</van-loading>
    </div>

    <!-- 内容区域 - 只有加载完成且有数据时才显示 -->
    <div class="content-container" v-else-if="!isLoading && article.title">
      <!-- 文章头部 -->
      <div class="article-header">
        <h1 class="article-title">{{ article.title }}</h1>
        <div class="article-meta">
          <div class="meta-info">
            <van-icon name="clock-o" /><span class="publish-date">{{ article.publishDate }}</span>
            <van-icon v-if="article.author" name="manager-o" /><span class="author">{{ article.author }}</span>
          </div>
        </div>
      </div>

      <!-- 文章封面 -->
      <div class="article-cover" v-if="article.coverImage">
        <img :src="article.coverImage" :alt="article.title" />
      </div>

      <!-- 文章内容 -->
      <div class="article-content">
        <div class="content-text" v-html="article.content"></div>
      </div>
    </div>

    <!-- 加载失败或无数据时的提示 -->
    <div class="error-container" v-else>
      <div class="error-message">
        <van-icon name="warning-o" size="48" color="#999" />
        <p>文章加载失败或不存在</p>
        <van-button type="primary" @click="$router.go(-1)">返回</van-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Toast } from 'vant'
import dayjs from 'dayjs'
import { useTitle } from '@vueuse/core';

// 导入接口
import { getArticleDetailAPI } from '@/api/index.js'

const route = useRoute()
const router = useRouter()

// 设置页面标题
useTitle(() => '新闻详情');

// 文章数据
const article = ref({})
// 加载状态
const isLoading = ref(true)

// 组件挂载时加载数据
onMounted(async () => {
  try {
    const articleId = route.params.id
    const { code, data } = await getArticleDetailAPI({ i: articleId })
    if (code) {
      let coverImage = data.file_list.photo ? data.file_list.photo.value : ''
      article.value = {
        ...data,
        id: data.id,
        title: data.post_title,
        content: data.post_content,
        publishDate: dayjs(data.post_date).format('YYYY-MM-DD HH:mm:ss'),
        author: data.author,
        coverImage: coverImage,
      }
    } else {
      Toast.fail('加载文章失败')
    }
  } catch (error) {
    console.error('加载文章出错:', error)
    Toast.fail('加载文章出错')
  } finally {
    // 无论成功还是失败,都结束loading状态
    isLoading.value = false
  }
})
</script>

<style scoped>
.page-container {
  background: #f5f5f5;
}

.loading-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f5f5f5;
  z-index: 999;
}

.content-container {
  background-color: #F2EBDB;
  min-height: 100vh;
}

.article-header {
  padding: 1rem;
}

.article-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: #8b4513;
  line-height: 1.4;
  margin: 0 0 1rem 0;
  text-align: center;
}

.article-meta {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 1rem;
  gap: 1rem;
}

.meta-info {
  display: flex;
  gap: 1rem;
  align-items: center;
}

.publish-date,
.author {
  font-size: 0.875rem;
  color: #8b4513;
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.article-cover {
  margin: 1rem 0;
}

.article-cover img {
  width: 100%;
  border-radius: 0.5rem;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.article-content {
  background: #f9f7f4;
  padding: 1.5rem;
  margin: 1rem 0;
  border-radius: 1rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  border: 1px solid #e8e3dc;
}

.content-text {
  font-size: 1rem;
  line-height: 1.8;
  color: #5d4e37;
}

.content-text :deep(p) {
  margin: 0 0 1rem 0;
  text-indent: 2em;
}

.content-text :deep(h3) {
  font-size: 1.125rem;
  font-weight: 600;
  color: #8b4513;
  text-align: center;
  margin: 1.5rem 0 1rem 0;
  text-indent: 0;
}

.content-text :deep(p:last-child) {
  margin-bottom: 0;
}

/* 富文本图片样式 */
.content-text :deep(img) {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0.5rem auto;
}

/* 富文本视频样式 */
.content-text :deep(video) {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0.5rem auto;
}

/* 错误状态样式 */
.error-container {
  background-color: #F2EBDB;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.error-message {
  text-align: center;
  padding: 2rem;
}

.error-message p {
  margin: 1rem 0;
  color: #999;
  font-size: 1rem;
}
</style>