hookehuyr

feat(收藏): 实现课程收藏功能并优化相关页面

- 新增 `favorite.js` API 文件,提供收藏列表、新增和取消收藏的接口
- 在 `CourseDetailPage.vue` 中实现收藏和取消收藏的逻辑,并添加交互反馈
- 在 `MyFavoritesPage.vue` 中替换模拟数据为真实接口调用,优化收藏课程加载逻辑
- 调整 `jsconfig.json` 配置文件,包含新增的 API 文件路径
......@@ -24,6 +24,6 @@
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*", "build/**/*", "vite.config.js"],
"include": ["src/**/*", "build/**/*", "vite.config.js", "src/api/.js"],
"exclude": ["node_modules", "dist"]
}
......
/*
* @Date: 2025-04-16 16:21:37
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-04-17 10:04:30
* @FilePath: /mlaj/src/api/favorite.js
* @Description: 收藏相关接口
*/
import { fn, fetch } from './fn'
const Api = {
GROUP_FAVORITE_LIST: '/srv/?a=group_favorite_list',
FAVORITE_ADD: '/srv/?a=group_favorite',
FAVORITE_CANCEL: '/srv/?a=group_unfavorite',
}
/**
* @description: 获取课程收藏列表
* @param: page 页码
* @param: limit 每页数量
* @return: data: { id: 收藏ID, title: 课程名称, price: 优惠价格, original_price: 原价, feature: 课程特色, highlights: 课程亮点, learning_goal: 学习目标, count: 课程章节数, cover: 封面图 }
*/
export const getGroupFavoriteListAPI = (params) => fn(fetch.get(Api.GROUP_FAVORITE_LIST, params))
/**
* @description: 新增收藏
* @param: group_id 课程ID
* @return: data: { }
*/
export const addFavoriteAPI = (params) => fn(fetch.post(Api.FAVORITE_ADD, params))
/**
* @description: 取消收藏
* @param: group_id 课程ID
* @return: data: { }
*/
export const cancelFavoriteAPI = (params) => fn(fetch.post(Api.FAVORITE_CANCEL, params))
This diff is collapsed. Click to expand it.
......@@ -2,7 +2,7 @@
<div class="bg-gradient-to-b from-green-50/70 to-white/90 min-h-screen pb-20">
<!-- 分类切换 -->
<div class="px-4 py-3">
<van-tabs v-model:active="activeTab" sticky swipeable title-active-color="#4caf50" color="#4caf50">
<van-tabs v-model:active="activeTab" @click-tab="onClickTab" sticky swipeable title-active-color="#4caf50" color="#4caf50">
<van-tab title="课程" name="courses">
<van-list
v-model:loading="coursesLoading"
......@@ -24,7 +24,7 @@
</van-tab>
<van-tab title="活动" name="activities">
<van-list
<!--<van-list
v-model:loading="activitiesLoading"
:finished="activitiesFinished"
finished-text="没有更多了"
......@@ -34,13 +34,13 @@
<ActivityCard v-for="activity in favoriteActivities" :key="activity.id" :activity="activity" />
</van-list>
<!-- 无数据提示 -->
<!~~ 无数据提示 ~~>
<div v-if="!activitiesLoading && favoriteActivities.length === 0" class="flex flex-col items-center justify-center py-12">
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
<p class="mt-4 text-gray-500">暂无收藏活动</p>
</div>
</div>-->
</van-tab>
</van-tabs>
</div>
......@@ -55,6 +55,9 @@ import ActivityCard from '@/components/ui/ActivityCard.vue';
import { courses as mockCourses, activities as mockActivities } from '@/utils/mockData';
import { useTitle } from '@vueuse/core';
// 导入接口
import { getGroupFavoriteListAPI } from '@/api/favorite';
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
......@@ -67,8 +70,8 @@ const favoriteActivities = ref([]);
// 课程列表加载状态
const coursesLoading = ref(false);
const coursesFinished = ref(false);
const coursePage = ref(1);
const coursePageSize = 10;
const coursePage = ref(0);
const courseLimit = ref(5);
// 活动列表加载状态
const activitiesLoading = ref(false);
......@@ -77,42 +80,41 @@ const activitiesPage = ref(1);
const activitiesPageSize = 10;
// 加载收藏课程
const onCoursesLoad = () => {
coursesLoading.value = true;
// 模拟异步加载
setTimeout(() => {
const start = (coursePage.value - 1) * coursePageSize;
const end = start + coursePageSize;
const newCourses = mockCourses.slice(start, end);
favoriteCourses.value.push(...newCourses);
coursesLoading.value = false;
if (newCourses.length < coursePageSize) {
coursesFinished.value = true;
} else {
coursePage.value += 1;
}
}, 1000);
const onCoursesLoad = async () => {
const nextPage = coursePage.value;
const res = await getGroupFavoriteListAPI({ limit: courseLimit.value, page: nextPage });
if (res.code) {
favoriteCourses.value = [...favoriteCourses.value, ...res.data];
coursesFinished.value = res.data.length < courseLimit.value;
coursePage.value = nextPage + 1;
}
coursesLoading.value = false;
};
// 加载收藏活动
const onActivitiesLoad = () => {
activitiesLoading.value = true;
// 模拟异步加载
setTimeout(() => {
const start = (activitiesPage.value - 1) * activitiesPageSize;
const end = start + activitiesPageSize;
const newActivities = mockActivities.slice(start, end);
// const onActivitiesLoad = () => {
// activitiesLoading.value = true;
// // 模拟异步加载
// setTimeout(() => {
// const start = (activitiesPage.value - 1) * activitiesPageSize;
// const end = start + activitiesPageSize;
// const newActivities = mockActivities.slice(start, end);
// favoriteActivities.value.push(...newActivities);
// activitiesLoading.value = false;
favoriteActivities.value.push(...newActivities);
activitiesLoading.value = false;
// if (newActivities.length < activitiesPageSize) {
// activitiesFinished.value = true;
// } else {
// activitiesPage.value += 1;
// }
// }, 1000);
// };
if (newActivities.length < activitiesPageSize) {
activitiesFinished.value = true;
} else {
activitiesPage.value += 1;
}
}, 1000);
// 切换标签页
const onClickTab = ({ name, title }) => {
if (name === 'activities') {
location.href = 'http://www.baidu.com'
}
};
</script>
......