hookehuyr

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

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

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
...@@ -103,8 +103,8 @@ ...@@ -103,8 +103,8 @@
103 </view> 103 </view>
104 </view> 104 </view>
105 105
106 - <!-- Hot Materials --> 106 + <!-- Hot Articles -->
107 - <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);"> 107 + <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);">
108 <!-- 背景装饰 --> 108 <!-- 背景装饰 -->
109 <view class="absolute -right-[60rpx] -top-[60rpx] w-[200rpx] h-[200rpx] bg-blue-50 rounded-full opacity-40 blur-[40rpx] pointer-events-none"></view> 109 <view class="absolute -right-[60rpx] -top-[60rpx] w-[200rpx] h-[200rpx] bg-blue-50 rounded-full opacity-40 blur-[40rpx] pointer-events-none"></view>
110 110
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
112 <!-- 标题带装饰 --> 112 <!-- 标题带装饰 -->
113 <view class="flex items-center"> 113 <view class="flex items-center">
114 <view class="w-[8rpx] h-[32rpx] bg-blue-600 rounded-full mr-[16rpx]"></view> 114 <view class="w-[8rpx] h-[32rpx] bg-blue-600 rounded-full mr-[16rpx]"></view>
115 - <text class="text-gray-900 text-[34rpx] font-bold tracking-tight">本周热门资料</text> 115 + <text class="text-gray-900 text-[34rpx] font-bold tracking-tight">本周热门文章</text>
116 </view> 116 </view>
117 117
118 <!-- 查看更多按钮优化 --> 118 <!-- 查看更多按钮优化 -->
...@@ -125,21 +125,20 @@ ...@@ -125,21 +125,20 @@
125 </view> 125 </view>
126 </view> 126 </view>
127 127
128 - <!-- Material List --> 128 + <!-- Article List -->
129 <view class="relative z-10 flex flex-col gap-[24rpx]"> 129 <view class="relative z-10 flex flex-col gap-[24rpx]">
130 - <!-- Material Items --> 130 + <!-- Article Items -->
131 - <MaterialCard 131 + <ArticleCard
132 - v-for="item in hotMaterials" 132 + v-for="item in hotArticles"
133 :key="item.id" 133 :key="item.id"
134 :id="item.id" 134 :id="item.id"
135 :title="item.title" 135 :title="item.title"
136 - :file-name="item.fileName" 136 + :excerpt="item.excerpt"
137 - :file-size="item.fileSize" 137 + :cover-url="item.coverUrl"
138 + :date="item.date"
138 :learners="item.learners" 139 :learners="item.learners"
139 :read-people-percent="item.readPeoplePercent" 140 :read-people-percent="item.readPeoplePercent"
140 :collected="item.collected" 141 :collected="item.collected"
141 - :extension="item.extension"
142 - :download-url="item.downloadUrl"
143 @collect-changed="handleCollectChanged(item, $event)" 142 @collect-changed="handleCollectChanged(item, $event)"
144 /> 143 />
145 </view> 144 </view>
...@@ -171,9 +170,9 @@ import TabBar from '@/components/navigation/TabBar.vue'; ...@@ -171,9 +170,9 @@ import TabBar from '@/components/navigation/TabBar.vue';
171 import IconFont from '@/components/icons/IconFont.vue'; 170 import IconFont from '@/components/icons/IconFont.vue';
172 import PlanFormContainer from '@/components/plan/PlanFormContainer.vue'; 171 import PlanFormContainer from '@/components/plan/PlanFormContainer.vue';
173 import ProductCard from '@/components/cards/ProductCard.vue'; 172 import ProductCard from '@/components/cards/ProductCard.vue';
174 -import MaterialCard from '@/components/cards/MaterialCard.vue'; 173 +import ArticleCard from '@/components/cards/ArticleCard.vue';
175 import { listAPI } from '@/api/get_product'; 174 import { listAPI } from '@/api/get_product';
176 -import { weekHotAPI } from '@/api/file'; 175 +import { weekHotAPI } from '@/api/article';
177 import { homeIconAPI } from '@/api/home'; 176 import { homeIconAPI } from '@/api/home';
178 import { usePlanSubmit } from '@/composables/usePlanSubmit'; 177 import { usePlanSubmit } from '@/composables/usePlanSubmit';
179 import { usePermission } from '@/composables/usePermission'; 178 import { usePermission } from '@/composables/usePermission';
...@@ -335,55 +334,58 @@ const fetchHotProducts = async () => { ...@@ -335,55 +334,58 @@ const fetchHotProducts = async () => {
335 }; 334 };
336 335
337 /** 336 /**
338 - * 热门资料数据 337 + * 热门文章数据
339 * 338 *
340 - * @description 本周热门资料列表数据,从 API 获取 339 + * @description 本周热门文章列表数据,从 API 获取
341 */ 340 */
342 -const hotMaterials = ref([]); 341 +const hotArticles = ref([]);
343 342
344 /** 343 /**
345 - * 热门资料加载状态 344 + * 热门文章加载状态
346 * 345 *
347 * @description 用于控制加载状态和空状态显示 346 * @description 用于控制加载状态和空状态显示
348 */ 347 */
349 -const hotMaterialsLoading = ref(false); 348 +const hotArticlesLoading = ref(false);
350 349
351 /** 350 /**
352 - * 获取本周热门资料 351 + * 获取本周热门文章
353 * 352 *
354 - * @description 调用 weekHotAPI 获取热门资料列表 353 + * @description 调用 weekHotAPI 获取热门文章列表
355 */ 354 */
356 -const fetchHotMaterials = async () => { 355 +const fetchHotArticles = async () => {
357 try { 356 try {
358 - hotMaterialsLoading.value = true; 357 + hotArticlesLoading.value = true;
359 const res = await weekHotAPI({ 358 const res = await weekHotAPI({
360 page: 0, 359 page: 0,
361 limit: 10 360 limit: 10
362 }); 361 });
363 362
364 if (res.code === 1 && res.data && res.data.list) { 363 if (res.code === 1 && res.data && res.data.list) {
365 - // 转换 API 数据格式为组件所需格式 364 + // 转换 API 数据格式为 ArticleCard 组件所需格式
366 - hotMaterials.value = res.data.list.map(item => { 365 + hotArticles.value = res.data.list
367 - return { 366 + .filter(item => item.id || item.meta_id) // 过滤掉没有 id 或 meta_id 的项
368 - id: item.meta_id, 367 + .map(item => {
369 - title: item.name || '未命名资料', 368 + // 优先使用 meta_id,其次使用 id(兼容不同 API 返回格式)
370 - fileName: item.name || '未命名文件', 369 + const itemId = item.meta_id || item.id;
371 - downloadUrl: item.src, 370 + return {
372 - fileSize: item.size, 371 + id: itemId,
373 - // 不在这里提取扩展名,让 MaterialCard 内部使用 extractExtensionFromFile 自动从 URL 解析 372 + title: item.post_title || '未命名文章',
374 - learners: `${item.read_people_count}人学习`, 373 + excerpt: item.post_excerpt || '',
375 - readPeoplePercent: item.read_people_percent, 374 + coverUrl: '', // TODO: 后续添加封面图字段
376 - collected: item.is_favorite 375 + date: item.post_date,
377 - } 376 + learners: item.read_people_count,
378 - }); 377 + readPeoplePercent: item.read_people_percent ? Number(item.read_people_percent) : null,
378 + collected: Boolean(item.is_favorite)
379 + }
380 + });
379 } else { 381 } else {
380 - hotMaterials.value = []; 382 + hotArticles.value = [];
381 } 383 }
382 } catch (err) { 384 } catch (err) {
383 - console.error('获取本周热门资料失败:', err); 385 + console.error('[Index] 获取本周热门文章失败:', err);
384 - hotMaterials.value = []; 386 + hotArticles.value = [];
385 } finally { 387 } finally {
386 - hotMaterialsLoading.value = false; 388 + hotArticlesLoading.value = false;
387 } 389 }
388 }; 390 };
389 391
...@@ -394,15 +396,15 @@ const go = useGo(); ...@@ -394,15 +396,15 @@ const go = useGo();
394 * 处理收藏状态改变 396 * 处理收藏状态改变
395 * 397 *
396 * @description 当用户点击收藏按钮时,更新本地状态 398 * @description 当用户点击收藏按钮时,更新本地状态
397 - * @param {Object} item - 资料对象 399 + * @param {Object} item - 文章对象
398 * @param {Object} newStatus - 新的状态 400 * @param {Object} newStatus - 新的状态
399 */ 401 */
400 const handleCollectChanged = (item, newStatus) => { 402 const handleCollectChanged = (item, newStatus) => {
401 console.log('[Index] 收藏状态改变:', item.title, newStatus.collected) 403 console.log('[Index] 收藏状态改变:', item.title, newStatus.collected)
402 // 找到对应的项并更新状态 404 // 找到对应的项并更新状态
403 - const material = hotMaterials.value.find(m => m.id === item.id) 405 + const article = hotArticles.value.find(a => a.id === item.id)
404 - if (material) { 406 + if (article) {
405 - material.collected = newStatus.collected 407 + article.collected = newStatus.collected
406 } 408 }
407 }; 409 };
408 410
...@@ -470,11 +472,11 @@ const openWebView = (url) => { ...@@ -470,11 +472,11 @@ const openWebView = (url) => {
470 }); 472 });
471 }; 473 };
472 474
473 -// 页面加载时获取首页图标、热卖产品和热门资料 475 +// 页面加载时获取首页图标、热卖产品和热门文章
474 useLoad(() => { 476 useLoad(() => {
475 fetchHomeIcons(); 477 fetchHomeIcons();
476 fetchHotProducts(); 478 fetchHotProducts();
477 - fetchHotMaterials(); 479 + fetchHotArticles();
478 }); 480 });
479 481
480 // 页面显示时刷新用户信息(更新 TabBar 红点状态) 482 // 页面显示时刷新用户信息(更新 TabBar 红点状态)
......