320 lines
9.6 KiB
Vue
320 lines
9.6 KiB
Vue
<template>
|
||
<a-card :bordered="false">
|
||
<div class="video-box">
|
||
<div class="video-title">{{ courseInfo.name }}</div>
|
||
<div class="video-main" v-if="curVideo">
|
||
<video-player
|
||
v-if="curVideo.courseWay === 1"
|
||
class="vjs-custom-skin"
|
||
ref="videoPlayer"
|
||
:options="playerOptions"
|
||
:playsinline="true"
|
||
@ended="onPlayerEnded($event)"
|
||
@timeupdate="onPlayerTimeupdate"
|
||
></video-player>
|
||
<a-spin :spinning="pdfLoading">
|
||
<div v-if="curVideo.courseWay === 2" style="width: 100%;height: 600px;">
|
||
<!-- https://www.gjtool.cn/pdfh5/git.pdf -->
|
||
<!-- :pdf="curVideo.videoAddress" -->
|
||
<vue-pdf-app
|
||
:pdf="curVideo.videoAddress"
|
||
:config="{
|
||
toolbar: false,
|
||
sidebar: false,
|
||
}"
|
||
@open="pdfOpened"
|
||
></vue-pdf-app>
|
||
</div>
|
||
</a-spin>
|
||
</div>
|
||
</div>
|
||
<div class="video-info">
|
||
<a-tabs :default-active-key="activeTab">
|
||
<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>
|
||
<!-- pdf阅读 -->
|
||
<PdfView ref="pdfView"></PdfView>
|
||
</a-card>
|
||
</template>
|
||
|
||
<script>
|
||
import _ from 'lodash'
|
||
import VuePdfApp from 'vue-pdf-app'
|
||
import 'vue-pdf-app/dist/icons/main.css'
|
||
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 PdfView from './PdfView.vue'
|
||
import OperationModule from './OperationModule.vue'
|
||
import StatisticalLearning from './StatisticalLearning.vue'
|
||
import { reqCourseDetail, reqCourseCatalogue, reqAddRecord } from '@/api/mycourse/index'
|
||
|
||
export default {
|
||
components: {
|
||
CourseCatalogue,
|
||
OperationModule,
|
||
SimulationTest,
|
||
ExamDialog,
|
||
StatisticalLearning,
|
||
PdfView,
|
||
videoPlayer,
|
||
VuePdfApp
|
||
},
|
||
data () {
|
||
return {
|
||
activeTab: '1',
|
||
query: {},
|
||
courseInfo: {},
|
||
catalogueList: [], // 目录列表
|
||
curVideo: {}, // 当前播放的视频信息
|
||
readComplete: false, // pdf文件是否已经阅读完成
|
||
pdfLoading: false, // 请求的是否不让pdf滚动
|
||
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] || ''
|
||
console.log('selected', selected)
|
||
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 && selected.coverPath.split(',')[0]
|
||
}
|
||
}
|
||
this.catalogueList = data
|
||
})
|
||
},
|
||
// pdf完全打开后
|
||
pdfOpened (pdfApp) {
|
||
const _this = this
|
||
setTimeout(() => {
|
||
document.querySelector('#viewerContainer').addEventListener('scroll', function (e) {
|
||
var target = e.target
|
||
const scrollTop = target.scrollTop
|
||
const scrollHeight = target.scrollHeight
|
||
const height = target.offsetHeight
|
||
const total = height + scrollTop + 500
|
||
if (total > scrollHeight) {
|
||
_this.reachBottom()
|
||
}
|
||
})
|
||
})
|
||
},
|
||
// pdf到达底部了
|
||
reachBottom: _.debounce(function () {
|
||
console.log('>>>>>>>>>>>>>>>>>>>onPlayerEnded')
|
||
console.log('到达了底部')
|
||
if (!this.readComplete && this.curVideo.status === 0) {
|
||
this.readComplete = true
|
||
this.readCompleteAjax()
|
||
}
|
||
}, 300),
|
||
// 视频已经阅读完成了
|
||
readCompleteAjax () {
|
||
this.pdfLoading = true
|
||
const { person } = this.$store.state.user
|
||
reqAddRecord({
|
||
personId: person.id,
|
||
projectId: this.$route.query.courseId,
|
||
courseId: this.curVideo.courseId,
|
||
coursewareId: this.curVideo.id
|
||
})
|
||
.then(res => {
|
||
this.$message.success('恭喜你,学习完成!')
|
||
})
|
||
.finally(() => {
|
||
this.pdfLoading = false
|
||
})
|
||
},
|
||
// 切换视频
|
||
changeVideo ({ item, pItem }) {
|
||
const _this = this
|
||
const change = function () {
|
||
if (document.querySelector('#viewerContainer')) {
|
||
document.querySelector('#viewerContainer').scrollTop = 0
|
||
}
|
||
setTimeout(() => {
|
||
_this.curVideo = item
|
||
// 只有视频会直接播放
|
||
if (item.courseWay === 1) {
|
||
const vid = _this.$refs.videoPlayer.player
|
||
vid.src(item.videoAddress)
|
||
vid.play()
|
||
} else {
|
||
_this.readComplete = false // 重置pdf阅读状态
|
||
}
|
||
// _this.openCourseExam() // 调试用
|
||
}, 300)
|
||
}
|
||
if (this.oldTime > 0 && _this.curVideo.status !== 1 && _this.curVideo.courseWay === 1) {
|
||
this.$confirm({
|
||
title: '确定要切换学习视频吗?',
|
||
content: '一但切换学习视频,您现在正在学习的视频学时将清0,确定要切换吗?',
|
||
onOk () {
|
||
change()
|
||
},
|
||
onCancel () {}
|
||
})
|
||
} else {
|
||
change()
|
||
}
|
||
},
|
||
// 当视频播放完毕的回调处理
|
||
onPlayerEnded () {
|
||
const { curVideo, courseInfo } = this
|
||
// 课件状态必须为未学状态
|
||
// 只有必修课切是视频文件才弹出课中检测
|
||
if (curVideo.status === 0 && courseInfo.trainType === 2 && curVideo.courseWay === 1) {
|
||
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>
|