feat: pdf阅读

This commit is contained in:
cgd 2022-03-16 14:39:54 +08:00
parent 2b89952c95
commit 8a3bc17497
5 changed files with 224 additions and 134 deletions

View File

@ -1,169 +1,178 @@
import request from '@/utils/request' import request from '@/utils/request'
const mycourseApi = { const mycourseApi = {
changePassword: '/sys/user/changePwd', changePassword: '/sys/user/changePwd',
mycourseList: 'myCourse/getMyCourseList', // 我的课程列表,课程搜索 mycourseList: 'myCourse/getMyCourseList', // 我的课程列表,课程搜索
addMyCourse: 'myCourse/addMyCourse', // 添加课程 addMyCourse: 'myCourse/addMyCourse', // 添加课程
centerList: 'focusTrain/getList', // 集中培训列表 centerList: 'focusTrain/getList', // 集中培训列表
centerDetail: 'focusTrain/getDetail', // 集中培训详情 centerDetail: 'focusTrain/getDetail', // 集中培训详情
centerJoin: 'project/terminalTrain/enroll', // 集中培训报名 centerJoin: 'project/terminalTrain/enroll', // 集中培训报名
centerSign: 'project/terminalTrain/sign', // 集中培训签到 centerSign: 'project/terminalTrain/sign', // 集中培训签到
recommendList: 'sys/recommend/listPage', // 系统推荐课程列表 recommendList: 'sys/recommend/listPage', // 系统推荐课程列表
recommendDetail: 'sys/recommend/detail', // 系统课程推荐详情 recommendDetail: 'sys/recommend/detail', // 系统课程推荐详情
trainPlanList: '/myCourse/getMyTrainPlanList', // 培训计划列表 trainPlanList: '/myCourse/getMyTrainPlanList', // 培训计划列表
getCourseDetail: 'myCourse/getCourseDetail', // 我的课程详情 getCourseDetail: 'myCourse/getCourseDetail', // 我的课程详情
getCourseCatalogue: 'myCourse/getCourseCatalogue', // 获取课程目录 getCourseCatalogue: 'myCourse/getCourseCatalogue', // 获取课程目录
reqCourseExam: 'testInClass/add', // 课中检测 reqCourseExam: 'testInClass/add', // 课中检测
simulateTestList: 'simulateTest/list', // 模拟测试列表 simulateTestList: 'simulateTest/list', // 模拟测试列表
simulateTestDetail: 'simulateTest/getQuestions', // 获取模拟测试详情 simulateTestDetail: 'simulateTest/getQuestions', // 获取模拟测试详情
operationList: 'classwork/list', // 作业列表 operationList: 'classwork/list', // 作业列表
reqOperationDetail: 'classwork/get', // 作业详情 reqOperationDetail: 'classwork/get', // 作业详情
reqOperationSubmit: 'classwork/submit', // 作业提交 reqOperationSubmit: 'classwork/submit', // 作业提交
getMyCourseList: 'studyStatistics/getMyTrainPlanList' // 课程学习统计 getMyCourseList: 'studyStatistics/getMyTrainPlanList', // 课程学习统计
addRecord: '/testInClass/addRecord' // pdf学习完成
} }
export function reqChangePassword (data) { export function reqAddRecord (data) {
return request({ return request({
url: mycourseApi.changePassword, url: mycourseApi.addRecord,
method: 'get', method: 'post',
params: data params: data
}) })
} }
export function reqChangePassword (data) {
return request({
url: mycourseApi.changePassword,
method: 'get',
params: data
})
}
export function reqCenterJoin (data) { export function reqCenterJoin (data) {
return request({ return request({
url: mycourseApi.centerJoin, url: mycourseApi.centerJoin,
method: 'POST', method: 'POST',
data: data data: data
}) })
} }
export function reqMycourseCount (params) { export function reqMycourseCount (params) {
return request({ return request({
url: mycourseApi.getMyCourseList, url: mycourseApi.getMyCourseList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqOperationDetail (params) { export function reqOperationDetail (params) {
return request({ return request({
url: mycourseApi.reqOperationDetail, url: mycourseApi.reqOperationDetail,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqOperationSubmit (params) { export function reqOperationSubmit (params) {
return request({ return request({
url: mycourseApi.reqOperationSubmit, url: mycourseApi.reqOperationSubmit,
method: 'post', method: 'post',
data: params data: params
}) })
} }
export function reqOperationList (params) { export function reqOperationList (params) {
return request({ return request({
url: mycourseApi.operationList, url: mycourseApi.operationList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqSimulateTestDetail (params) { export function reqSimulateTestDetail (params) {
return request({ return request({
url: mycourseApi.simulateTestDetail, url: mycourseApi.simulateTestDetail,
method: 'post', method: 'post',
params: params params: params
}) })
} }
export function reqSimulateTestList (data) { export function reqSimulateTestList (data) {
return request({ return request({
url: mycourseApi.simulateTestList, url: mycourseApi.simulateTestList,
method: 'post', method: 'post',
data: data, data: data,
params: data params: data
}) })
} }
export function reqMyCourseList (params) { export function reqMyCourseList (params) {
return request({ return request({
url: mycourseApi.mycourseList, url: mycourseApi.mycourseList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqMyTrainPlanList (params) { export function reqMyTrainPlanList (params) {
return request({ return request({
url: mycourseApi.trainPlanList, url: mycourseApi.trainPlanList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqAddMyCourse (params) { export function reqAddMyCourse (params) {
return request({ return request({
url: mycourseApi.addMyCourse, url: mycourseApi.addMyCourse,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqCourseCenterList (params) { export function reqCourseCenterList (params) {
return request({ return request({
url: mycourseApi.centerList, url: mycourseApi.centerList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqCourseCenterDetail (params) { export function reqCourseCenterDetail (params) {
return request({ return request({
url: mycourseApi.centerDetail, url: mycourseApi.centerDetail,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqRecommendList (params) { export function reqRecommendList (params) {
return request({ return request({
url: mycourseApi.recommendList, url: mycourseApi.recommendList,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function recommendDetail (params) { export function recommendDetail (params) {
return request({ return request({
url: mycourseApi.recommendDetail, url: mycourseApi.recommendDetail,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqCourseDetail (params) { export function reqCourseDetail (params) {
return request({ return request({
url: mycourseApi.getCourseDetail, url: mycourseApi.getCourseDetail,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqCourseCatalogue (params) { export function reqCourseCatalogue (params) {
return request({ return request({
url: mycourseApi.getCourseCatalogue, url: mycourseApi.getCourseCatalogue,
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function reqCourseExam (params, data) { export function reqCourseExam (params, data) {
return request({ return request({
url: mycourseApi.reqCourseExam, url: mycourseApi.reqCourseExam,
method: 'post', method: 'post',
params: params, params: params,
data: data data: data
}) })
} }

View File

@ -23,11 +23,13 @@
]" ]"
> >
<VideoOne <VideoOne
v-if="j.courseWay === 1"
theme="filled" theme="filled"
:fill="j.id === curVideo.id ? '#1890ff' : j.status === 1 ? '#26bd71' : '#ccc'" :fill="j.id === curVideo.id ? '#1890ff' : j.status === 1 ? '#26bd71' : '#ccc'"
style="margin-right: 6px;" style="margin-right: 6px;"
size="1.2em" size="1.2em"
></VideoOne> ></VideoOne>
<FilePdf v-else theme="filled" size="1.2em" :fill="j.id === curVideo.id ? '#1890ff' : j.status === 1 ? '#26bd71' : '#ccc'" style="margin-right: 6px;"/>
{{ index + 1 }}.{{ k + 1 }} {{ index + 1 }}.{{ k + 1 }}
{{ j.name }} {{ j.name }}
</div> </div>
@ -57,9 +59,9 @@
</template> </template>
<script> <script>
import { VideoOne, Round, History } from '@icon-park/vue' import { VideoOne, Round, History, FilePdf } from '@icon-park/vue'
export default { export default {
components: { VideoOne, Round, History }, components: { VideoOne, Round, History, FilePdf },
props: { props: {
catalogueList: { catalogueList: {
type: Array, type: Array,

View File

@ -22,7 +22,8 @@ export default {
data () { data () {
return { return {
title: 'PDF阅读', title: 'PDF阅读',
visible: true, visible: false,
data: '', //
config: { config: {
toolbar: false, toolbar: false,
sidebar: false sidebar: false
@ -34,6 +35,11 @@ export default {
}, },
methods: { methods: {
initData () {}, initData () {},
open (data) {
console.log('data', data)
this.data = data
this.visible = true
},
pagesRendered (pdfApp) { pagesRendered (pdfApp) {
console.log('pdfApp', pdfApp) console.log('pdfApp', pdfApp)
setTimeout(() => { setTimeout(() => {
@ -47,7 +53,7 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
::v-deep .ant-modal-body{ ::v-deep .ant-modal-body {
padding-top: 0; padding-top: 0;
padding-bottom: 0; padding-bottom: 0;
} }

View File

@ -2,8 +2,9 @@
<a-card :bordered="false"> <a-card :bordered="false">
<div class="video-box"> <div class="video-box">
<div class="video-title">{{ courseInfo.name }}</div> <div class="video-title">{{ courseInfo.name }}</div>
<div class="video-main"> <div class="video-main" v-if="curVideo">
<video-player <video-player
v-if="curVideo.courseWay === 1"
class="vjs-custom-skin" class="vjs-custom-skin"
ref="videoPlayer" ref="videoPlayer"
:options="playerOptions" :options="playerOptions"
@ -11,10 +12,24 @@
@ended="onPlayerEnded($event)" @ended="onPlayerEnded($event)"
@timeupdate="onPlayerTimeupdate" @timeupdate="onPlayerTimeupdate"
></video-player> ></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> </div>
<div class="video-info"> <div class="video-info">
<a-tabs :default-active-key="activeTab" @change="tabChange"> <a-tabs :default-active-key="activeTab">
<a-tab-pane key="1" tab="课程目录"> <a-tab-pane key="1" tab="课程目录">
<div class="tab-box"> <div class="tab-box">
<CourseCatalogue <CourseCatalogue
@ -44,11 +59,14 @@
<!-- 课中考试 --> <!-- 课中考试 -->
<ExamDialog ref="examDialog" :curVideo="curVideo" @success="answerSuccess"></ExamDialog> <ExamDialog ref="examDialog" :curVideo="curVideo" @success="answerSuccess"></ExamDialog>
<!-- pdf阅读 --> <!-- pdf阅读 -->
<PdfView></PdfView> <PdfView ref="pdfView"></PdfView>
</a-card> </a-card>
</template> </template>
<script> <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 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css' import 'vue-video-player/src/custom-theme.css'
import { videoPlayer } from 'vue-video-player' import { videoPlayer } from 'vue-video-player'
@ -58,7 +76,7 @@ import ExamDialog from './ExamDialog.vue'
import PdfView from './PdfView.vue' import PdfView from './PdfView.vue'
import OperationModule from './OperationModule.vue' import OperationModule from './OperationModule.vue'
import StatisticalLearning from './StatisticalLearning.vue' import StatisticalLearning from './StatisticalLearning.vue'
import { reqCourseDetail, reqCourseCatalogue } from '@/api/mycourse/index' import { reqCourseDetail, reqCourseCatalogue, reqAddRecord } from '@/api/mycourse/index'
export default { export default {
components: { components: {
@ -68,7 +86,8 @@ export default {
ExamDialog, ExamDialog,
StatisticalLearning, StatisticalLearning,
PdfView, PdfView,
videoPlayer videoPlayer,
VuePdfApp
}, },
data () { data () {
return { return {
@ -77,6 +96,8 @@ export default {
courseInfo: {}, courseInfo: {},
catalogueList: [], // catalogueList: [], //
curVideo: {}, // curVideo: {}, //
readComplete: false, // pdf
pdfLoading: false, // pdf
playerOptions: {}, playerOptions: {},
isMousedown: false, isMousedown: false,
oldTime: 0, oldTime: 0,
@ -111,6 +132,7 @@ export default {
}) })
} }
const selected = videoList[0] || '' const selected = videoList[0] || ''
console.log('selected', selected)
if (selected) { if (selected) {
this.curVideo = selected this.curVideo = selected
this.playerOptions = { this.playerOptions = {
@ -144,17 +166,69 @@ export default {
this.catalogueList = data 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 }) { changeVideo ({ item, pItem }) {
const _this = this const _this = this
const vid = this.$refs.videoPlayer.player
const change = function () { const change = function () {
_this.curVideo = item if (document.querySelector('#viewerContainer')) {
vid.src(item.videoAddress) document.querySelector('#viewerContainer').scrollTop = 0
vid.play() }
// _this.openCourseExam() // 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) { if (this.oldTime > 0 && _this.curVideo.status !== 1 && _this.curVideo.courseWay === 1) {
this.$confirm({ this.$confirm({
title: '确定要切换学习视频吗?', title: '确定要切换学习视频吗?',
content: '一但切换学习视频,您现在正在学习的视频学时将清0,确定要切换吗?', content: '一但切换学习视频,您现在正在学习的视频学时将清0,确定要切换吗?',
@ -167,14 +241,14 @@ export default {
change() change()
} }
}, },
tabChange (key) {
// this.$refs.videoPlayer.player.play() //
// this.$refs.videoPlayer.player.pause() //
// this.$refs.videoPlayer.player.src('src') //
},
// //
onPlayerEnded () { onPlayerEnded () {
this.openCourseExam() const { curVideo, courseInfo } = this
//
//
if (curVideo.status === 0 && courseInfo.trainType === 2 && curVideo.courseWay === 1) {
this.openCourseExam()
}
}, },
// //
openCourseExam () { openCourseExam () {
@ -191,8 +265,7 @@ export default {
_this.$refs.examDialog.getExamQuestion() _this.$refs.examDialog.getExamQuestion()
}, },
onCancel () { onCancel () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {}).catch(() => console.log('Oops errors!'))
}).catch(() => console.log('Oops errors!'))
}, },
wrapClassName: 'dialogTest' wrapClassName: 'dialogTest'
}) })
@ -240,7 +313,7 @@ export default {
margin: 0 auto; margin: 0 auto;
} }
.learn-exam-dialog ::v-deep .ant-modal-confirm-btns:first-child{ .learn-exam-dialog ::v-deep .ant-modal-confirm-btns:first-child {
display: none; display: none;
} }
</style> </style>

View File

@ -37,7 +37,7 @@
<a-tag v-if="record.status === 3" color="green">已完成</a-tag> <a-tag v-if="record.status === 3" color="green">已完成</a-tag>
</span> </span>
<template slot="schedule" slot-scope="text, record"> <template slot="schedule" slot-scope="text, record">
<a-progress :percent="record.schedule" /> <a-progress v-if="record.schedule || record.schedule === 0" :percent="record.schedule" />
</template> </template>
<template slot="learnHours" slot-scope="text, record">{{ record.learnHours }}小时</template> <template slot="learnHours" slot-scope="text, record">{{ record.learnHours }}小时</template>
<span slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">