hookehuyr

feat(StudyDetailPage): 添加课程目录弹出层及课程切换功能

在StudyDetailPage页面中新增课程目录弹出层,支持用户查看课程目录并切换课程。点击目录项时,更新URL并重新获取课程数据,确保页面内容与所选课程一致。同时优化了课程数据的加载逻辑,提升用户体验。
......@@ -156,12 +156,45 @@
<van-button type="primary" size="small" @click="submitComment">发送</van-button>
</div>
</div>
<!-- 课程目录弹出层 -->
<van-popup v-model:show="showCatalog" position="bottom" round closeable safe-area-inset-bottom
style="height: 80%">
<div class="flex flex-col h-full">
<!-- 固定头部 -->
<div class="flex-none px-4 py-3 border-b bg-white sticky top-0 z-10">
<div class="text-lg font-medium">课程目录</div>
</div>
<!-- 可滚动的目录列表 -->
<div class="flex-1 overflow-y-auto px-4 py-2">
<div v-if="course_lessons.length" class="space-y-4">
<div v-for="(lesson, index) in course_lessons" :key="index"
@click="handleLessonClick(lesson)"
class="bg-white p-4 cursor-pointer hover:bg-gray-50 transition-colors border-b border-gray-200 relative">
<div v-if="lesson.progress > 0 && lesson.progress < 100"
class="absolute top-2 right-2 px-2 py-1 bg-green-100 text-green-600 text-xs rounded">
上次看到</div>
<div class="text-black text-base font-medium mb-2">{{ lesson.title }}</div>
<div class="flex items-center text-sm text-gray-500">
<span>{{ course_type_maps[lesson.course_type] }}</span>
<span v-if="course_type_maps[lesson.course_type]" class="mx-2">|</span>
<span>开课时间: {{ dayjs(lesson.schedule_time).format('YYYY-MM-DD') }}</span>
<span class="mx-2">|</span>
<span>课程时长: {{ lesson.duration }} 分钟</span>
</div>
</div>
</div>
<van-empty v-else description="暂无目录" />
</div>
</div>
</van-popup>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useTitle } from '@vueuse/core';
import VideoPlayer from '@/components/ui/VideoPlayer.vue';
import AudioPlayer from '@/components/ui/AudioPlayer.vue';
......@@ -169,10 +202,12 @@ import dayjs from 'dayjs';
import { formatDate } from '@/utils/tools'
// 导入接口
import { getScheduleCourseAPI, getGroupCommentListAPI, addGroupCommentAPI, addGroupCommentLikeAPI, delGroupCommentLikeAPI } from '@/api/course';
import { getScheduleCourseAPI, getGroupCommentListAPI, addGroupCommentAPI, addGroupCommentLikeAPI, delGroupCommentLikeAPI, getCourseDetailAPI } from '@/api/course';
const route = useRoute();
const router = useRouter();
const course = ref(null);
const activeTab = ref('intro');
const newComment = ref('');
const showCatalog = ref(false);
......@@ -181,6 +216,15 @@ const videoPlayerRef = ref(null);
const showCommentPopup = ref(false);
const popupComment = ref('');
// 课程目录相关
const course_lessons = ref([]);
const course_type_maps = ref({
video: '视频',
audio: '音频',
image: '图片',
file: '文件',
});
// 开始播放视频
const startPlay = async () => {
isPlaying.value = true;
......@@ -299,6 +343,34 @@ const commentCount = ref(0);
const commentList = ref([]);
const courseFile = ref({});
// 处理课程切换
const handleLessonClick = async (lesson) => {
showCatalog.value = false; // 关闭目录弹窗
isPlaying.value = false; // 重置播放状态
// 更新URL地址,不触发页面重新加载
router.replace({ params: { id: lesson.id } });
// 重新获取课程数据
const { code, data } = await getScheduleCourseAPI({ i: lesson.id });
if (code) {
course.value = data;
courseFile.value = data.file;
// 音频列表处理
if (data.course_type === 'audio') {
audioList.value = [data.file];
}
// 获取评论列表
const comment = await getGroupCommentListAPI({ group_id: data.group_id, schedule_id: data.id });
if (comment.code) {
commentList.value = comment.data.comment_list;
commentCount.value = comment.data.comment_count;
}
}
};
onMounted(async () => {
// 延迟设置topWrapper和bottomWrapper的高度
setTimeout(() => {
......@@ -334,7 +406,14 @@ onMounted(async () => {
commentList.value = comment.data.comment_list;
commentCount.value = comment.data.comment_count;
}
// 获取课程目录
const detail = await getCourseDetailAPI({ i: course.value.group_id });
if (detail.code) {
course_lessons.value = detail.data.schedule || [];
}
}
}
})
......