index.vue 5.6 KB
<!--
 * @Date: 2026-02-27
 * @Description: 文章收藏列表页 - 复用 favorites 页面结构
-->
<template>
  <view class="h-screen bg-gray-50 flex flex-col overflow-hidden">
    <view class="bg-gray-50 z-10">
      <NavHeader title="我的收藏文章" />
    </view>

    <!-- LoadMoreList 组件 -->
    <LoadMoreList
      :list="currentList"
      :page="currentPage"
      :page-size="pageSize"
      :has-more="hasMore"
      :loading="loading"
      :loading-more="loadingMore"
      key-field="id"
      :show-header="false"
      :has-footer="false"
      @load-more="handleLoadMore"
    >
      <!-- 列表项 -->
      <template #item="{ item }">
        <ArticleCard
          :id="item.id"
          :title="item.title"
          :excerpt="item.excerpt"
          :cover-url="item.coverUrl"
          :date="item.date"
          :collected="item.collected"
          @viewed="onView(item)"
          @collect-changed="handleCollectChanged(item, $event)"
        />
      </template>
    </LoadMoreList>
  </view>
</template>

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

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

/**
 * 当前列表数据
 */
const currentList = ref([])

/**
 * 当前页码(从0开始)
 */
const currentPage = ref(0)

/**
 * 每页数量
 */
const pageSize = 20

/**
 * 是否还有更多数据
 */
const hasMore = ref(true)

/**
 * 首次加载状态
 */
const loading = ref(false)

/**
 * 加载更多状态
 */
const loadingMore = ref(false)

/**
 * 获取文章收藏列表
 *
 * @param {Object} params - 请求参数
 * @param {number} params.page - 页码(从0开始)
 * @param {number} params.limit - 每页数量
 * @param {boolean} isLoadMore - 是否为加载更多
 */
const fetchFavoritesList = async (params = {}, isLoadMore = false) => {
  try {
    if (isLoadMore) {
      loadingMore.value = true
    } else {
      loading.value = true
    }

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

    const res = USE_MOCK_DATA
      ? await mockArticleFavoriteAPI(params)
      : await favoriteAPI({
          page: String(params.page),
          limit: String(params.limit)
        })

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

      const processedList = res.data.list.map(item => ({
        id: item.id,
        title: item.post_title || '未命名文章',
        excerpt: item.post_excerpt || '',
        coverUrl: '',
        date: item.post_date || '',
        collected: true // 收藏列表中的文章都是已收藏的
      }))

      if (isLoadMore) {
        currentList.value = [...currentList.value, ...processedList]
      } else {
        currentList.value = processedList
      }

      hasMore.value = res.data.list.length >= params.limit
    } else {
      if (!isLoadMore) {
        currentList.value = []
      }
      Taro.showToast({
        title: res.msg || '获取收藏列表失败',
        icon: 'none'
      })
    }
  } catch (err) {
    console.error('[Article Favorites] 获取收藏列表失败:', err)
    if (!isLoadMore) {
      currentList.value = []
    }
    Taro.showToast({
      title: '网络错误,请稍后重试',
      icon: 'none'
    })
  } finally {
    if (isLoadMore) {
      loadingMore.value = false
    } else {
      loading.value = false
    }
  }
}

/**
 * 处理收藏状态改变
 */
const handleCollectChanged = (item, newStatus) => {
  console.log('[Article Favorites] 收藏状态改变:', item.title, newStatus.collected)

  if (!newStatus.collected) {
    // 取消收藏,从列表中移除
    const index = currentList.value.findIndex(i => i.id === item.id)
    if (index !== -1) {
      currentList.value.splice(index, 1)
    }
  }
}

/**
 * 查看文章
 */
const onView = (item) => {
  console.log('[Article Favorites] 查看文章:', item.title)
  // 跳转到文章详情页
  Taro.navigateTo({
    url: `/pages/article-detail/index?id=${item.id}`
  })
}

/**
 * 处理加载更多事件
 */
const handleLoadMore = async (page) => {
  console.log('[Article Favorites] 加载更多,页码:', page)
  currentPage.value = page
  await fetchFavoritesList({ page: page, limit: pageSize }, true)
}

/**
 * 刷新收藏列表
 */
const refreshList = async () => {
  console.log('[Article Favorites] 刷新列表')
  currentPage.value = 0
  hasMore.value = true
  await fetchFavoritesList({ page: 0, limit: pageSize })
}

/**
 * 页面加载时获取列表
 */
useLoad(() => {
  console.log('[Article Favorites] 页面加载,获取列表')
  currentPage.value = 0
  hasMore.value = true
  fetchFavoritesList({ page: 0, limit: pageSize })
})

/**
 * 监听收藏更新事件
 */
onMounted(() => {
  console.log('[Article Favorites] 注册事件监听')

  const unsubscribe = eventBus.on(Events.FAVORITES_UPDATE, async () => {
    console.log('[Article Favorites] 收到收藏更新事件')
    await refreshList()
  })

  onUnmounted(() => {
    unsubscribe()
    console.log('[Article Favorites] 取消事件监听')
  })
})
</script>

<style lang="less">
/* LoadMoreList 组件已内置样式 */
</style>