225 lines
5.4 KiB
Vue
225 lines
5.4 KiB
Vue
<template>
|
||
<view class="chapter-detail-page">
|
||
<!-- 自定义导航栏 -->
|
||
<nav-bar :title="$t('courseDetails.chapter')" />
|
||
|
||
<!-- 页面内容 -->
|
||
<view class="page-content">
|
||
<!-- 视频播放器 -->
|
||
<view class="video-section">
|
||
<VideoPlayer
|
||
v-if="videoList.length > 0"
|
||
ref="videoPlayerRef"
|
||
v-model:current-index="currentVideoIndex"
|
||
:video-list="videoList"
|
||
:countdown-seconds="5"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 课程和章节信息 -->
|
||
<view class="info-section">
|
||
<view class="info-item">
|
||
<text class="label">{{ $t('courseDetails.courseInfo') }}:</text>
|
||
<text class="value">{{ courseTitle }}</text>
|
||
</view>
|
||
<view class="info-item">
|
||
<text class="label">{{ $t('courseDetails.chapterInfo') }}:</text>
|
||
<text class="value">{{ chapterTitle }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 视频列表 -->
|
||
<view v-if="videoList.length > 0" class="video-list-section">
|
||
<view class="section-title">{{ $t('courseDetails.videoTeaching') }}</view>
|
||
<wd-radio-group v-model="currentVideoIndex" shape="button" >
|
||
<wd-radio v-for="(video, index) in videoList" :key="video.id" :value="index" class="mb-2!">
|
||
【{{ video.type == 2 ? $t('courseDetails.audio') : $t('courseDetails.video') }}】{{ index + 1 }}
|
||
</wd-radio>
|
||
</wd-radio-group>
|
||
</view>
|
||
|
||
<!-- 选项卡 -->
|
||
<wd-tabs v-model="currentTab" class="tabs-section" lineWidth="30">
|
||
<!-- 章节介绍 -->
|
||
<wd-tab name="chapterIntro" :title="$t('courseDetails.chapterIntro')">
|
||
<!-- 章节封面 -->
|
||
<image
|
||
v-if="chapterDetail?.imgUrl"
|
||
:src="chapterDetail.imgUrl"
|
||
mode="widthFix"
|
||
class="chapter-image"
|
||
@click="previewImage(chapterDetail.imgUrl)"
|
||
/>
|
||
|
||
<!-- 章节内容 -->
|
||
<view v-if="chapterDetail?.content" v-html="chapterDetail.content"></view>
|
||
|
||
<view class="copyright">
|
||
<text>{{ $t('courseDetails.copyright') }}</text>
|
||
</view>
|
||
</wd-tab>
|
||
<!-- 思考题 -->
|
||
<wd-tab v-if="chapterDetail?.questions" name="thinkingQuestion" :title="$t('courseDetails.thinkingQuestion')">
|
||
<view v-html="chapterDetail.questions"></view>
|
||
<!-- <view v-else class="no-question">
|
||
<wd-divider>{{ $t('courseDetails.noQuestion') }}</wd-divider>
|
||
</view> -->
|
||
</wd-tab>
|
||
</wd-tabs>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { courseApi } from '@/api/modules/course'
|
||
import VideoPlayer from '@/components/video-player/index.vue'
|
||
import type { IChapterDetail } from '@/types/course'
|
||
import type { IVideoInfo } from '@/types/video'
|
||
|
||
// 页面参数
|
||
const chapterId = ref<number>(0)
|
||
const courseTitle = ref('')
|
||
const chapterTitle = ref('')
|
||
|
||
// 页面数据
|
||
const chapterDetail = ref<IChapterDetail | null>(null)
|
||
const videoList = ref<IVideoInfo[]>([])
|
||
const currentVideoIndex = ref(0)
|
||
const activeVideoIndex = ref(0)
|
||
const currentTab = ref('chapterIntro')
|
||
|
||
// 视频播放器引用
|
||
const videoPlayerRef = ref<any>(null)
|
||
|
||
/**
|
||
* 页面加载
|
||
*/
|
||
onLoad((options: any) => {
|
||
chapterId.value = parseInt(options.id)
|
||
courseTitle.value = options.courseTitle || ''
|
||
chapterTitle.value = options.title || ''
|
||
|
||
loadChapterDetail()
|
||
})
|
||
|
||
/**
|
||
* 加载章节详情
|
||
*/
|
||
const loadChapterDetail = async () => {
|
||
const res = await courseApi.getChapterDetail(chapterId.value)
|
||
if (res.code === 0 && res.data) {
|
||
chapterDetail.value = res.data.detail
|
||
videoList.value = res.data.videos || []
|
||
|
||
// 如果有历史播放记录,定位到对应视频
|
||
if (res.data.current) {
|
||
const index = videoList.value.findIndex((v:any) => v.id === res.data.current)
|
||
if (index !== -1) {
|
||
currentVideoIndex.value = index
|
||
activeVideoIndex.value = index
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 预览图片
|
||
*/
|
||
const previewImage = (url: string) => {
|
||
uni.previewImage({
|
||
urls: [url],
|
||
current: url
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.chapter-detail-page {
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.video-section {
|
||
background-color: #000;
|
||
height: 400rpx;
|
||
}
|
||
|
||
.info-section {
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
|
||
.info-item {
|
||
margin-bottom: 15rpx;
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
color: #999;
|
||
}
|
||
|
||
.value {
|
||
color: #333;
|
||
}
|
||
}
|
||
}
|
||
|
||
.video-list-section {
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
margin-top: 20rpx;
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
color: #2979ff;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
}
|
||
|
||
.tabs-section {
|
||
background-color: #fff;
|
||
margin-top: 20rpx;
|
||
|
||
:deep(.wd-tabs__nav) {
|
||
border-bottom: 1px solid #2979ff;
|
||
}
|
||
:deep(.wd-tab__body) {
|
||
padding: 30rpx;
|
||
font-size: 28rpx;
|
||
line-height: 1.8;
|
||
color: #666;
|
||
word-break: break-all;
|
||
}
|
||
:deep(.wd-tabs__line) {
|
||
bottom: 0;
|
||
}
|
||
}
|
||
|
||
.chapter-image {
|
||
width: 100%;
|
||
display: block;
|
||
margin-bottom: 20rpx;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.copyright {
|
||
margin-top: 20rpx;
|
||
padding-top: 20rpx;
|
||
border-top: 1px solid #f0f0f0;
|
||
text-align: center;
|
||
font-size: 24rpx;
|
||
color: #ff4444;
|
||
}
|
||
|
||
.no-question {
|
||
padding: 80rpx 0;
|
||
text-align: center;
|
||
}
|
||
</style>
|