Files
taimed-international-app/pages/course/details/chapter.vue
2025-12-03 14:10:27 +08:00

222 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="chapter-detail-page">
<!-- 自定义导航栏 -->
<nav-bar :title="$t('courseDetails.chapter')" />
<!-- 页面内容 -->
<view class="page-content">
<!-- 视频播放器 -->
<view v-if="videoList.length > 0" class="video-section">
<VideoPlayer
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, IVideo } from '@/types/course'
// 页面参数
const chapterId = ref<number>(0)
const courseTitle = ref('')
const chapterTitle = ref('')
// 页面数据
const chapterDetail = ref<IChapterDetail | null>(null)
const videoList = ref<IVideo[]>([])
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;
}
.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>