243 lines
6.9 KiB
Vue
243 lines
6.9 KiB
Vue
<template>
|
||
<a-card :bordered="false">
|
||
<div class="video-box">
|
||
<div class="video-title">{{ courseInfo.name }}</div>
|
||
<div class="video-main">
|
||
<video-player
|
||
class="vjs-custom-skin"
|
||
ref="videoPlayer"
|
||
:options="playerOptions"
|
||
:playsinline="true"
|
||
@ended="onPlayerEnded($event)"
|
||
@timeupdate="onPlayerTimeupdate"
|
||
></video-player>
|
||
</div>
|
||
</div>
|
||
<div class="video-info">
|
||
<a-tabs :default-active-key="activeTab" @change="tabChange">
|
||
<a-tab-pane key="1" tab="课程目录">
|
||
<div class="tab-box">
|
||
<CourseCatalogue
|
||
@changeVideo="changeVideo"
|
||
:catalogueList="catalogueList"
|
||
:curVideo="curVideo"
|
||
></CourseCatalogue>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="2" tab="模拟测试">
|
||
<div class="tab-box">
|
||
<SimulationTest></SimulationTest>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="3" tab="作业">
|
||
<div class="tab-box">
|
||
<OperationModule></OperationModule>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="4" tab="学习统计">
|
||
<div class="tab-box">
|
||
<StatisticalLearning :courseInfo="courseInfo"></StatisticalLearning>
|
||
</div>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
</div>
|
||
<!-- 课中考试 -->
|
||
<ExamDialog ref="examDialog" :curVideo="curVideo" @success="answerSuccess"></ExamDialog>
|
||
</a-card>
|
||
</template>
|
||
|
||
<script>
|
||
import 'video.js/dist/video-js.css'
|
||
import 'vue-video-player/src/custom-theme.css'
|
||
import { videoPlayer } from 'vue-video-player'
|
||
import CourseCatalogue from './CourseCatalogue.vue'
|
||
import SimulationTest from './SimulationTest.vue'
|
||
import ExamDialog from './ExamDialog.vue'
|
||
import OperationModule from './OperationModule.vue'
|
||
import StatisticalLearning from './StatisticalLearning.vue'
|
||
import { reqCourseDetail, reqCourseCatalogue } from '@/api/mycourse/index'
|
||
|
||
export default {
|
||
components: {
|
||
CourseCatalogue,
|
||
OperationModule,
|
||
SimulationTest,
|
||
ExamDialog,
|
||
StatisticalLearning,
|
||
videoPlayer
|
||
},
|
||
data () {
|
||
return {
|
||
activeTab: '1',
|
||
query: {},
|
||
courseInfo: {},
|
||
catalogueList: [], // 目录列表
|
||
curVideo: {}, // 当前播放的视频信息
|
||
playerOptions: {},
|
||
isMousedown: false,
|
||
oldTime: 0,
|
||
newTime: 0,
|
||
maxTime: 0
|
||
}
|
||
},
|
||
mounted () {
|
||
const query = this.$route.query
|
||
this.query = query
|
||
this.initData()
|
||
},
|
||
methods: {
|
||
initData () {
|
||
const { person } = this.$store.state.user
|
||
// 获取课程详情
|
||
reqCourseDetail({ personId: person.id, id: this.query.courseId }).then(res => {
|
||
this.courseInfo = res.data
|
||
})
|
||
// 获取课程目录
|
||
reqCourseCatalogue({ personId: person.id, projectId: this.query.courseId }).then(res => {
|
||
const data = res.data
|
||
let videoList = []
|
||
if (Array.isArray(data)) {
|
||
data.map(item => {
|
||
videoList = [...videoList, ...item.courseList]
|
||
if (Array.isArray(item.courseList)) {
|
||
item.courseList.map(j => {
|
||
j.courseId = item.id
|
||
})
|
||
}
|
||
})
|
||
}
|
||
const selected = videoList[0] || ''
|
||
if (selected) {
|
||
this.curVideo = selected
|
||
this.playerOptions = {
|
||
height: '500',
|
||
autoplay: false,
|
||
muted: false,
|
||
language: 'zh-CN',
|
||
sources: [
|
||
{
|
||
type: 'video/mp4',
|
||
src: selected.videoAddress
|
||
}
|
||
],
|
||
controlBar: {
|
||
/* 使用children的形式可以控制每一个控件的位置,以及显示与否 */
|
||
children: [
|
||
{ name: 'playToggle' }, // 播放按钮
|
||
{ name: 'currentTimeDisplay' }, // 当前已播放时间
|
||
{ name: 'progressControl' }, // 播放进度条
|
||
{ name: 'durationDisplay' }, // 总时间
|
||
{
|
||
name: 'volumePanel', // 音量控制
|
||
inline: false // 不使用水平方式
|
||
},
|
||
{ name: 'FullscreenToggle' } // 全屏
|
||
]
|
||
},
|
||
poster: selected.coverPath
|
||
}
|
||
}
|
||
this.catalogueList = data
|
||
})
|
||
},
|
||
// 切换视频
|
||
changeVideo ({ item, pItem }) {
|
||
const _this = this
|
||
const vid = this.$refs.videoPlayer.player
|
||
const change = function () {
|
||
_this.curVideo = item
|
||
vid.src(item.videoAddress)
|
||
vid.play()
|
||
// _this.openCourseExam() // 调试用
|
||
}
|
||
if (this.oldTime > 0 && _this.curVideo.status !== 1) {
|
||
this.$confirm({
|
||
title: '确定要切换学习视频吗?',
|
||
content: '一但切换学习视频,您现在正在学习的视频学时将清0,确定要切换吗?',
|
||
onOk () {
|
||
change()
|
||
},
|
||
onCancel () {}
|
||
})
|
||
} else {
|
||
change()
|
||
}
|
||
},
|
||
tabChange (key) {
|
||
// this.$refs.videoPlayer.player.play() // 播放
|
||
// this.$refs.videoPlayer.player.pause() // 暂停
|
||
// this.$refs.videoPlayer.player.src('src') // 重置进度条复制代码
|
||
},
|
||
// 当视频播放完毕的回调处理
|
||
onPlayerEnded () {
|
||
this.openCourseExam()
|
||
},
|
||
// 打开课中检查
|
||
openCourseExam () {
|
||
const _this = this
|
||
const curVideo = this.curVideo
|
||
if (curVideo.status === 1) return
|
||
this.$confirm({
|
||
title: '课中检查',
|
||
content:
|
||
'课程学习完成后都会随机出现1道小题,答对题目,方可继续下一部分学习,您有2次机会。否则之前上一小段学习时间不计算学时,需要重新学习!',
|
||
okCancel: false,
|
||
onOk () {
|
||
_this.$refs.examDialog.show()
|
||
_this.$refs.examDialog.getExamQuestion()
|
||
},
|
||
onCancel () {
|
||
return new Promise((resolve, reject) => {
|
||
}).catch(() => console.log('Oops errors!'))
|
||
},
|
||
wrapClassName: 'dialogTest'
|
||
})
|
||
},
|
||
// 禁止快进
|
||
onPlayerTimeupdate () {
|
||
const { oldTime, maxTime } = this
|
||
const vd = this.$refs.videoPlayer.player
|
||
var current = vd.currentTime()
|
||
if (current < maxTime) {
|
||
} else if (current - oldTime > 1) {
|
||
vd.currentTime(oldTime)
|
||
} else {
|
||
this.oldTime = current
|
||
if (oldTime >= maxTime) {
|
||
this.maxTime = oldTime
|
||
}
|
||
}
|
||
},
|
||
answerSuccess () {
|
||
this.curVideo.status = 1
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.video-title {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
margin-bottom: 15px;
|
||
color: #333;
|
||
}
|
||
|
||
.video-info {
|
||
margin-top: 15px;
|
||
}
|
||
|
||
::v-deep .ant-tabs-nav-scroll {
|
||
text-align: center;
|
||
}
|
||
.tab-box {
|
||
max-width: 800px;
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.learn-exam-dialog ::v-deep .ant-modal-confirm-btns:first-child{
|
||
display: none;
|
||
}
|
||
</style>
|