index.vue 5.68 KB
<!--
 * @Date: 2026-02-27
 * @Description: 本周热门文章页 - 改造版(原热门资料页)
-->
<template>
  <LoadMoreList
    :list="currentList"
    :page="currentPage"
    :page-size="pageSize"
    :has-more="hasMore"
    :loading="loading"
    :loading-more="loadingMore"
    key-field="id"
    :has-footer="false"
    @load-more="handleLoadMore"
  >
    <!-- 头部 -->
    <template #header>
      <NavHeader title="本周热门文章" />
    </template>

    <!-- 列表项 -->
    <template #item="{ item }">
      <ArticleCard
        :id="item.id"
        :title="item.title"
        :excerpt="item.excerpt"
        :cover-url="item.coverUrl"
        :date="item.date"
        :learners="item.learners"
        :read-people-percent="item.readPeoplePercent"
        :collected="item.collected"
        @collect-changed="handleCollectChanged(item, $event)"
      />
    </template>
  </LoadMoreList>
</template>

<script setup>
import { ref } from 'vue'
import Taro, { useLoad } from '@tarojs/taro'
import LoadMoreList from '@/components/list/LoadMoreList'
import NavHeader from '@/components/navigation/NavHeader.vue'
import ArticleCard from '@/components/cards/ArticleCard.vue'
import { weekHotAPI } from '@/api/article'
import { mockArticleWeekHotAPI } from '@/utils/mockData'
import { USE_MOCK_DATA } from '@/config/app'

// ⚠️ MOCK 数据开关 - 统一从 @/config/app 导入
// const USE_MOCK_DATA = process.env.NODE_ENV === 'development'

/**
 * 当前列表数据
 * @type {Ref<Array<any>>}
 */
const currentList = ref([])

/**
 * 当前页码(从0开始)
 * @type {Ref<number>}
 */
const currentPage = ref(0)

/**
 * 每页数量
 * @type {number}
 */
const pageSize = 20

/**
 * 是否还有更多数据
 * @type {Ref<boolean>}
 */
const hasMore = ref(true)

/**
 * 首次加载状态
 * @type {Ref<boolean>}
 */
const loading = ref(false)

/**
 * 加载更多状态
 * @type {Ref<boolean>}
 */
const loadingMore = ref(false)

/**
 * 处理收藏状态改变
 *
 * @description 当用户点击收藏按钮时,更新本地状态
 * @param {Object} item - 文章对象
 * @param {Object} newStatus - 新的状态 { collected: boolean }
 */
const handleCollectChanged = (item, newStatus) => {
  console.log('[Week Hot] 收藏状态改变:', item.title, newStatus.collected)
  // 找到对应的项并更新状态
  const article = currentList.value.find(a => a.id === item.id)
  if (article) {
    article.collected = newStatus.collected
  }
}

/**
 * 获取本周热门文章列表
 *
 * @param {Object} params - 请求参数
 * @param {number} params.page - 页码(从0开始)
 * @param {number} params.limit - 每页数量
 * @param {boolean} isLoadMore - 是否为加载更多
 * @returns {Promise<void>}
 */
const fetchWeekHotList = async (params = {}, isLoadMore = false) => {
  try {
    // 如果是加载更多,使用 loadingMore 状态,否则使用 loading 状态
    if (isLoadMore) {
      loadingMore.value = true
    } else {
      loading.value = true
    }

    console.log('[Week Hot] 请求参数:', params)
    console.log('[Week Hot] 使用 Mock 数据:', USE_MOCK_DATA)

    // 根据开关选择使用真实 API 或 Mock 数据
    const res = USE_MOCK_DATA
      ? await mockArticleWeekHotAPI(params)
      : await weekHotAPI(params)

    if (res.code === 1 && res.data) {
      console.log('[Week Hot] 数据:', res.data)

      // 处理列表数据
      if (res.data.list?.length) {
        // 映射为 ArticleCard 需要的格式
        const listData = res.data.list.map(item => ({
          id: item.id,
          title: item.post_title || '未命名文章',
          excerpt: item.post_excerpt || '',
          coverUrl: item.file_list?.icon?.value || '',
          date: item.post_date || '',
          collected: item.is_favorite === 1 || item.is_favorite === '1' || item.is_favorite === true,
          learners: item.read_people_count,
          readPeoplePercent: item.read_people_percent
        }))

        if (isLoadMore) {
          // 加载更多:追加数据
          currentList.value = [...currentList.value, ...listData]
        } else {
          // 首次加载或刷新:替换数据
          currentList.value = listData
        }

        // 判断是否还有更多数据
        // 如果返回的数据量少于请求的量,说明没有更多了
        hasMore.value = listData.length >= params.limit
      } else {
        // 没有数据了
        if (isLoadMore) {
          hasMore.value = false
        } else {
          currentList.value = []
        }
      }
    } else {
      Taro.showToast({
        title: res.msg || '获取热门文章失败',
        icon: 'none',
        duration: 2000
      })
    }
  } catch (error) {
    console.error('[Week Hot] 获取热门文章失败:', error)
    Taro.showToast({
      title: '加载失败',
      icon: 'error',
      duration: 2000
    })
  } finally {
    if (isLoadMore) {
      loadingMore.value = false
    } else {
      loading.value = false
    }
  }
}

/**
 * 页面加载时获取数据
 */
useLoad(async (options) => {
  console.log('[Week Hot] 页面参数:', options)

  // 重置分页状态
  currentPage.value = 0
  hasMore.value = true

  // 获取本周热门文章列表
  await fetchWeekHotList({ page: 0, limit: pageSize })
})

/**
 * 处理加载更多事件
 *
 * @param {number} page - 下一页页码
 * @returns {Promise<void>}
 */
const handleLoadMore = async (page) => {
  console.log('[Week Hot] 加载更多,页码:', page)

  // 更新页码
  currentPage.value = page

  // 加载下一页数据
  await fetchWeekHotList(
    { page: page, limit: pageSize },
    true  // 标记为加载更多
  )
}
</script>

<style lang="less">
/* LoadMoreList 组件已内置样式,此处无需额外样式 */
</style>