| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- <template>
- <div class="course-detail-page" v-if="currentCourse">
- <!-- <el-page-header @back="goBack">
- <template #content>{{ currentCourse.title }}</template>
- </el-page-header> -->
- <Breadcrumb />
-
- <div class="course-detail">
- <div class="course-main">
- <div class="course-video">
- <!-- 视频播放器占位 -->
- <div class="video-player">
- <VideoPlayer
- ref="videoPlayer"
- :src="currentVideoUrl"
- :poster="currentCourse.cover"
- @play="onPlayerPlay"
- @pause="onPlayerPause"
- @ended="onPlayerEnded"
- @timeupdate="onPlayerTimeupdate"
- @loadedmetadata="onPlayerLoadedmetadata"
- @error="onPlayerError"
- @ready="onPlayerReady"
- />
- <!-- <img :src="currentCourse.cover" :alt="currentCourse.title">
- <div class="play-button">▶</div> -->
- </div>
-
- <div class="video-info">
- <h2>{{ currentCourse.title }}</h2>
- <div class="course-meta">
- <span>讲师:{{ currentCourse.teacher }}</span>
- <span>价格:¥{{ currentCourse.price }}</span>
- </div>
- <p class="course-desc">{{ currentCourse.description }}</p>
- <el-button type="primary" size="large">立即学习</el-button>
- </div>
- </div>
-
- <div class="course-chapters">
- <h3>课程章节</h3>
- <el-collapse>
- <el-collapse-item
- v-for="chapter in currentCourseChapters"
- :key="chapter.id"
- :title="chapter.title"
- @click="playVideo(video)"
- >
- <div
- v-for="video in chapter.videos"
- :key="video.id"
- class="chapter-video"
- >
- <el-icon><VideoPlay /></el-icon>
- {{ video.title }} ({{ video.duration }})
- </div>
- </el-collapse-item>
- </el-collapse>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { onMounted,ref } from 'vue'
- import { useRoute, useRouter } from 'vue-router'
- import { useCourseStore } from '@/pinia/courseStore'
- import { VideoPlay } from '@element-plus/icons-vue'
- import VideoPlayer from '@/components/VideoPlayer.vue'
- import DGTMessage from '@/utils/message'
- const route = useRoute()
- const router = useRouter()
- const courseStore = useCourseStore()
- const courseId = route.params.id
- const currentCourse = ref(null)
- const currentCourseChapters = ref(null)
- const videoPlayer = ref(null)
- // const currentVideoUrl = ref('')
- // const currentVideoUrl = ref('http://jcxxpt.oss-cn-beijing.aliyuncs.com/common/2025/12/19/actmOvmq0xOBc8448561c73a066a523821c6f7ae4868_20251219094240A008.mp4')
- // const currentVideoUrl = ref('http://baomiai.oss-cn-shanghai.aliyuncs.com/video/2025/12/30/123_20251226133117A047_20251230095248A001.mp4?response-content-disposition=inline&response-content-type=video%2Fmp4&x-oss-date=20251230T015258Z&x-oss-expires=7200&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI5tG5dEtkqwDGcU6AtaYE%2F20251230%2Fcn-shanghai%2Foss%2Faliyun_v4_reque')
- const currentVideoUrl = ref('http://baomiai.oss-cn-shanghai.aliyuncs.com/video/2025/12/30/123_20251226133117A047_20251230095248A001.mp4?response-content-disposition=inline&x-oss-date=20251230T015720Z&x-oss-expires=7199&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI5tG5dEtkqwDGcU6AtaYE%2F20251230%2Fcn-shanghai%2Foss%2Faliyun_v4_request&x-oss-signature=f93c20421dcfdc6822cd03d42ae66f8a28acd2c4d25c79ce16e2312537eabaa5')
- const currentPlayingVideoId = ref(null)
- const currentVideoDuration = ref(0)
- const currentPlayTime = ref(0)
- onMounted(() => {
- courseStore.fetchCourseDetail(courseId)
- courseStore.fetchCourseChapters(courseId)
-
- currentCourse.value = courseStore.currentCourse
- currentCourseChapters.value = courseStore.currentCourseChapters
- })
- const goBack = () => {
- router.back()
- }
- // 播放指定视频
- const playVideo = (video) => {
- if (!video) return
-
- // 更新当前播放的视频ID
- currentPlayingVideoId.value = video.id
-
- // 这里可以根据video.id从API获取实际的视频地址
- // 暂时使用模拟地址
- const videoUrl = `https://example.com/videos/${video.id}.mp4`
-
- // 更新视频源
- currentVideoUrl.value = videoUrl
-
- // 播放视频
- if (videoPlayer.value) {
- videoPlayer.value.play()
- }
- }
- // 播放器事件处理
- const onPlayerPlay = () => {
- console.log('视频开始播放')
- }
- const onPlayerPause = () => {
- console.log('视频暂停')
- }
- const onPlayerEnded = () => {
- console.log('视频播放结束')
-
- // 自动播放下一个视频
- playNextVideo()
- }
- const onPlayerTimeupdate = (time) => {
- currentPlayTime.value = time
- // 这里可以保存播放进度
- console.log('当前播放时间:', time)
- }
- const onPlayerLoadedmetadata = (duration) => {
- currentVideoDuration.value = duration
- console.log('视频时长:', duration)
- }
- const onPlayerError = (error) => {
- console.error('视频播放错误:', error)
- DGTMessage.error('视频播放失败,请稍后再试')
- }
- const onPlayerReady = (player) => {
- console.log('播放器就绪', player)
- // 可以在这里进行高级操作
- }
- // 播放下一个视频
- const playNextVideo = () => {
- if (!currentCourseChapters.value || currentPlayingVideoId.value === null) return
-
- // 查找当前播放视频的位置
- let currentIndex = -1
- let chapterIndex = -1
-
- for (let i = 0; i < currentCourseChapters.value.length; i++) {
- const chapter = currentCourseChapters.value[i]
- const index = chapter.videos.findIndex(v => v.id === currentPlayingVideoId.value)
-
- if (index !== -1) {
- chapterIndex = i
- currentIndex = index
- break
- }
- }
-
- // 如果找到当前视频
- if (chapterIndex !== -1 && currentIndex !== -1) {
- const currentChapter = currentCourseChapters.value[chapterIndex]
-
- // 如果当前章节还有下一个视频
- if (currentIndex < currentChapter.videos.length - 1) {
- playVideo(currentChapter.videos[currentIndex + 1])
- }
- // 如果是当前章节最后一个视频,且有下一个章节
- else if (chapterIndex < currentCourseChapters.value.length - 1) {
- playVideo(currentCourseChapters.value[chapterIndex + 1].videos[0])
- }
- }
- }
- // 格式化时间
- const formatTime = (seconds) => {
- if (!seconds || isNaN(seconds)) return '00:00'
-
- const minutes = Math.floor(seconds / 60)
- const secs = Math.floor(seconds % 60)
- return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
- }
- </script>
- <style scoped lang="scss">
- .course-detail {
- .course-video {
- display: flex;
- gap: 20px;
- margin-bottom: 40px;
- // height: 500px; /* 设置容器高度,可根据需要调整 */
-
- @media (max-width: 768px) {
- flex-direction: column;
- }
-
- .video-player {
- flex: 2;
- position: relative;
- // height: 500px;
-
- img {
- width: 100%;
- height: auto;
- border-radius: 8px;
- }
-
- .play-button {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 80px;
- height: 80px;
- background: rgba(0,0,0,0.5);
- color: white;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 30px;
- cursor: pointer;
- }
- }
-
- .video-info {
- flex: 1;
-
- h2 {
- font-size: 1.8rem;
- margin-bottom: 15px;
- }
-
- .course-meta {
- margin-bottom: 15px;
- color: #666;
-
- span {
- display: block;
- margin-bottom: 5px;
- }
- }
-
- .course-desc {
- margin-bottom: 20px;
- line-height: 1.6;
- }
- }
- }
-
- .course-chapters {
- h3 {
- font-size: 1.5rem;
- margin-bottom: 15px;
- }
-
- .chapter-video {
- padding: 10px;
- border-bottom: 1px solid #eee;
- cursor: pointer;
-
- &:hover {
- background-color: #f5f5f5;
- }
- }
- }
- }
- </style>
|