feat(index): 首页热门资料改为热门文章
- 将"本周热门资料"改为"本周热门文章" - 使用 ArticleCard 替换 MaterialCard - 更新 API 调用从 file/weekHotAPI 到 article/weekHotAPI - 调整数据映射格式适配文章字段 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Showing
1 changed file
with
48 additions
and
46 deletions
| ... | @@ -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 红点状态) | ... | ... |
-
Please register or login to post a comment