hookehuyr

feat(index): 首页热门资料改为热门文章

- 将"本周热门资料"改为"本周热门文章"
- 使用 ArticleCard 替换 MaterialCard
- 更新 API 调用从 file/weekHotAPI 到 article/weekHotAPI
- 调整数据映射格式适配文章字段

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
......@@ -103,8 +103,8 @@
</view>
</view>
<!-- Hot Materials -->
<view v-if="hotMaterials.length > 0" class="relative bg-white rounded-[32rpx] p-[32rpx] mb-[48rpx] border border-gray-100 overflow-hidden" style="box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.04);">
<!-- Hot Articles -->
<view v-if="hotArticles.length > 0" class="relative bg-white rounded-[32rpx] p-[32rpx] mb-[48rpx] border border-gray-100 overflow-hidden" style="box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.04);">
<!-- 背景装饰 -->
<view class="absolute -right-[60rpx] -top-[60rpx] w-[200rpx] h-[200rpx] bg-blue-50 rounded-full opacity-40 blur-[40rpx] pointer-events-none"></view>
......@@ -112,7 +112,7 @@
<!-- 标题带装饰 -->
<view class="flex items-center">
<view class="w-[8rpx] h-[32rpx] bg-blue-600 rounded-full mr-[16rpx]"></view>
<text class="text-gray-900 text-[34rpx] font-bold tracking-tight">本周热门资料</text>
<text class="text-gray-900 text-[34rpx] font-bold tracking-tight">本周热门文章</text>
</view>
<!-- 查看更多按钮优化 -->
......@@ -125,21 +125,20 @@
</view>
</view>
<!-- Material List -->
<!-- Article List -->
<view class="relative z-10 flex flex-col gap-[24rpx]">
<!-- Material Items -->
<MaterialCard
v-for="item in hotMaterials"
<!-- Article Items -->
<ArticleCard
v-for="item in hotArticles"
:key="item.id"
:id="item.id"
:title="item.title"
:file-name="item.fileName"
:file-size="item.fileSize"
:excerpt="item.excerpt"
:cover-url="item.coverUrl"
:date="item.date"
:learners="item.learners"
:read-people-percent="item.readPeoplePercent"
:collected="item.collected"
:extension="item.extension"
:download-url="item.downloadUrl"
@collect-changed="handleCollectChanged(item, $event)"
/>
</view>
......@@ -171,9 +170,9 @@ import TabBar from '@/components/navigation/TabBar.vue';
import IconFont from '@/components/icons/IconFont.vue';
import PlanFormContainer from '@/components/plan/PlanFormContainer.vue';
import ProductCard from '@/components/cards/ProductCard.vue';
import MaterialCard from '@/components/cards/MaterialCard.vue';
import ArticleCard from '@/components/cards/ArticleCard.vue';
import { listAPI } from '@/api/get_product';
import { weekHotAPI } from '@/api/file';
import { weekHotAPI } from '@/api/article';
import { homeIconAPI } from '@/api/home';
import { usePlanSubmit } from '@/composables/usePlanSubmit';
import { usePermission } from '@/composables/usePermission';
......@@ -335,55 +334,58 @@ const fetchHotProducts = async () => {
};
/**
* 热门资料数据
* 热门文章数据
*
* @description 本周热门资料列表数据,从 API 获取
* @description 本周热门文章列表数据,从 API 获取
*/
const hotMaterials = ref([]);
const hotArticles = ref([]);
/**
* 热门资料加载状态
* 热门文章加载状态
*
* @description 用于控制加载状态和空状态显示
*/
const hotMaterialsLoading = ref(false);
const hotArticlesLoading = ref(false);
/**
* 获取本周热门资料
* 获取本周热门文章
*
* @description 调用 weekHotAPI 获取热门资料列表
* @description 调用 weekHotAPI 获取热门文章列表
*/
const fetchHotMaterials = async () => {
const fetchHotArticles = async () => {
try {
hotMaterialsLoading.value = true;
hotArticlesLoading.value = true;
const res = await weekHotAPI({
page: 0,
limit: 10
});
if (res.code === 1 && res.data && res.data.list) {
// 转换 API 数据格式为组件所需格式
hotMaterials.value = res.data.list.map(item => {
// 转换 API 数据格式为 ArticleCard 组件所需格式
hotArticles.value = res.data.list
.filter(item => item.id || item.meta_id) // 过滤掉没有 id 或 meta_id 的项
.map(item => {
// 优先使用 meta_id,其次使用 id(兼容不同 API 返回格式)
const itemId = item.meta_id || item.id;
return {
id: item.meta_id,
title: item.name || '未命名资料',
fileName: item.name || '未命名文件',
downloadUrl: item.src,
fileSize: item.size,
// 不在这里提取扩展名,让 MaterialCard 内部使用 extractExtensionFromFile 自动从 URL 解析
learners: `${item.read_people_count}人学习`,
readPeoplePercent: item.read_people_percent,
collected: item.is_favorite
id: itemId,
title: item.post_title || '未命名文章',
excerpt: item.post_excerpt || '',
coverUrl: '', // TODO: 后续添加封面图字段
date: item.post_date,
learners: item.read_people_count,
readPeoplePercent: item.read_people_percent ? Number(item.read_people_percent) : null,
collected: Boolean(item.is_favorite)
}
});
} else {
hotMaterials.value = [];
hotArticles.value = [];
}
} catch (err) {
console.error('获取本周热门资料失败:', err);
hotMaterials.value = [];
console.error('[Index] 获取本周热门文章失败:', err);
hotArticles.value = [];
} finally {
hotMaterialsLoading.value = false;
hotArticlesLoading.value = false;
}
};
......@@ -394,15 +396,15 @@ const go = useGo();
* 处理收藏状态改变
*
* @description 当用户点击收藏按钮时,更新本地状态
* @param {Object} item - 资料对象
* @param {Object} item - 文章对象
* @param {Object} newStatus - 新的状态
*/
const handleCollectChanged = (item, newStatus) => {
console.log('[Index] 收藏状态改变:', item.title, newStatus.collected)
// 找到对应的项并更新状态
const material = hotMaterials.value.find(m => m.id === item.id)
if (material) {
material.collected = newStatus.collected
const article = hotArticles.value.find(a => a.id === item.id)
if (article) {
article.collected = newStatus.collected
}
};
......@@ -470,11 +472,11 @@ const openWebView = (url) => {
});
};
// 页面加载时获取首页图标、热卖产品和热门资料
// 页面加载时获取首页图标、热卖产品和热门文章
useLoad(() => {
fetchHomeIcons();
fetchHotProducts();
fetchHotMaterials();
fetchHotArticles();
});
// 页面显示时刷新用户信息(更新 TabBar 红点状态)
......