index.vue 3.61 KB
<template>
  <view class="message-detail-page">
    <view class="page-content">
      <view class="hero-card">
        <text class="hero-title">消息详情</text>
        <text class="hero-desc">
          进入详情页后,当前消息会在 mock 中自动标记为已读,返回列表即可看到状态变化。
        </text>
      </view>

      <view v-if="loading" class="placeholder-card">
        <text class="section-title">加载中</text>
        <text class="section-desc">正在获取消息详情...</text>
      </view>

      <view v-else-if="detail" class="detail-card">
        <view class="detail-meta">
          <text class="detail-category">{{ detail.category }}</text>
          <text class="detail-time">{{ detail.created_time }}</text>
        </view>
        <text class="detail-title">{{ detail.title }}</text>
        <text class="detail-content">{{ detail.content }}</text>
      </view>

      <view v-else class="placeholder-card">
        <text class="section-title">未找到消息</text>
        <text class="section-desc">
          当前消息不存在,或者真实接口还没有返回这条详情数据。
        </text>
      </view>

      <button class="back-btn" @tap="goBack">返回消息列表</button>
    </view>
  </view>
</template>

<script setup>
import { ref } from 'vue'
import Taro, { useLoad } from '@tarojs/taro'
import { messageDetailAPI } from '@/api/message'

const loading = ref(true)
const detail = ref(null)

const fetchMessageDetail = async (id) => {
  loading.value = true

  try {
    const response = await messageDetailAPI({ id })
    if (response?.code === 1) {
      detail.value = response.data
      return
    }

    detail.value = null
    Taro.showToast({
      title: response?.msg || '获取详情失败',
      icon: 'none',
    })
  } catch (error) {
    console.error('获取消息详情失败:', error)
    detail.value = null
  } finally {
    loading.value = false
  }
}

const goBack = () => {
  Taro.navigateBack()
}

useLoad((options) => {
  const id = String(options?.id || '').trim()
  if (!id) {
    loading.value = false
    return
  }

  fetchMessageDetail(id)
})
</script>

<style lang="less">
.message-detail-page {
  min-height: 100vh;
  background:
    radial-gradient(circle at top right, rgba(166, 121, 57, 0.16), transparent 30%),
    linear-gradient(180deg, #fffaf4 0%, #f4f6fb 100%);

  .page-content {
    padding: 32rpx 24rpx 48rpx;
    box-sizing: border-box;
  }

  .hero-card,
  .detail-card,
  .placeholder-card {
    padding: 32rpx;
    border-radius: 28rpx;
    background: rgba(255, 255, 255, 0.94);
    border: 2rpx solid rgba(166, 121, 57, 0.08);
    box-shadow: 0 20rpx 60rpx rgba(15, 23, 42, 0.06);
    box-sizing: border-box;
  }

  .hero-title,
  .section-title,
  .detail-title {
    display: block;
    color: #111827;
  }

  .hero-title,
  .detail-title {
    font-size: 40rpx;
    font-weight: 700;
  }

  .hero-desc,
  .section-desc,
  .detail-content {
    display: block;
    margin-top: 16rpx;
    font-size: 26rpx;
    line-height: 1.8;
    color: #6b7280;
    white-space: pre-wrap;
  }

  .detail-card,
  .placeholder-card,
  .back-btn {
    margin-top: 24rpx;
  }

  .detail-meta {
    display: flex;
    align-items: center;
    gap: 16rpx;
    margin-bottom: 18rpx;
  }

  .detail-category {
    padding: 8rpx 14rpx;
    border-radius: 999rpx;
    font-size: 22rpx;
    color: #92400e;
    background: #fef3c7;
  }

  .detail-time {
    font-size: 22rpx;
    color: #9ca3af;
  }

  .back-btn {
    border-radius: 999rpx;
    font-size: 28rpx;
    line-height: 84rpx;
    color: #0f172a;
    background: #ffffff;
    border: 2rpx solid #d1d5db;
  }
}
</style>