You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

653 lines
16 KiB

<template>
<div class="wrap pb">
<breadcrumb :routes.sync="routes" />
<div class="flex">
<div class="cover" :class="{ 'is-word': showMask1 }">
<img v-if="coverUrl" :src="coverUrl" alt="" width="100%" height="100%">
<template v-else-if="iframeSrc">
<iframe class="inner fileIframe" id="fileIframe" :src="iframeSrc" frameborder="0"></iframe>
<template v-if="showMask">
<div class="mask" style="width: 500px;height: 30px;top: 53px;right: 320px"></div>
<div class="mask" style="width: 175px;height: 30px;top: 53px;right: 5px"></div>
</template>
<template v-if="showMask1">
<div class="word-mask" style="height: 40px;"></div>
<div class="word-mask2" style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div>
</template>
<template v-if="showMask2">
<div class="excel-mask1" style="height: 48px;"></div>
</template>
</template>
<div class="pdf inner" v-else-if="pdfSrc">
<p class="arrow">
<span @click="changePdfPage(0)" class="turn el-icon-arrow-left" :class="{ grey: currentPage == 1 }"></span>
{{ currentPage }} / {{ pageCount }}
<span @click="changePdfPage(1)" class="turn el-icon-arrow-right"
:class="{ grey: currentPage == pageCount }"></span>
</p>
<pdf class="pdf-wrap" :src="pdfSrc" :page="currentPage" @num-pages="pageCount = $event"
@page-loaded="currentPage = $event" @loaded="loadPdfHandler">
</pdf>
</div>
<div class="inner" v-else-if="playAuth">
<div class="video_wid" id="player"></div>
</div>
<div class="inner" v-else-if="videoSrc">
<video class="video" :key="videoSrc" width="100%" height="100%" autoplay controls>
<source :src="videoSrc" type="video/mp4">
您的浏览器不支持 video 标签。
</video>
</div>
</div>
<div class="catalog">
<div class="list">
<h4 class="title">{{ courseName }}</h4>
<div class="desc-wrap">
<div class="desc" :class="{ active: desShrink }" v-html="description"></div>
<i class="arrow" :class="{ active: desShrink }" v-if="description && description.length > 40">
</i>
</div>
<div class="chapters">
<template v-if="chapterList && chapterList.length">
<div class="chapter" v-for="(item, index) in chapterList" :key="index">
<div class="chapterName">{{ item.name }}</div>
<div class="section" v-if="item.subsectionList.length">
<div v-for="(section, i) in item.subsectionList" :key="i" @click="preview(section, item.name)">
<p class="sectionName" :class="{ active: curLink === `${item.name}${section.name}` }">
<img v-if="section.fileType === 'pptx'" src="@/assets/img/exts/ppt.png" alt="">
<img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt="">
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'"
src="@/assets/img/exts/word.png" alt="">
<img v-else-if="section.fileType === 'txt'" src="@/assets/img/exts/txt.png" alt="">
<img v-else-if="section.fileType === 'pdf'" src="@/assets/img/exts/pdf.png" alt="">
<img v-else src="@/assets/img/exts/pic.png" alt="">
{{ section.name }}
</p>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import pdf from "vue-pdf";
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import breadcrumb from '@/components/breadcrumb'
import Setting from "@/setting"
import util from "@/libs/util"
export default {
data () {
return {
routes: [],
startTime: Date.now(), // 页面进来的时间
id: this.$route.query.id,
video: '',
chapterList: [],
courseName: '',
description: '',
coverUrl: '',
playAuth: '',
player: null,
previewImg: '',
iframeSrc: '',
videoSrc: '',
isWord: false,
isPPT: false,
isExcel: false,
showMask: false,
showMask1: false,
showMask2: false,
closePosi: {
top: '80px'
},
pdfVisible: false,
pdfSrc: '',
currentPage: 0, // pdf文件页码
pageCount: 0, // pdf文件总页数
fileType: 'pdf', // 文件类型
desShrink: false,
curLink: "", // 当前选中
};
},
computed: {
...mapState({
courseId: state => state.courseId,
classId: state => state.classId,
}),
},
components: { pdf, breadcrumb },
mounted () {
this.insertScript()
this.getData()
},
destroyed () {
// 记录播放时长
util.session.get(Setting.tokenKey) && this.$post(this.api.playRecordSave, {
courseId: this.id,
courseType: 1,
playTime: Math.ceil((Date.now() - this.startTime) / 1000 / 60)
}).then(({ data }) => { }).catch(res => { })
},
methods: {
...mapMutations('project', [
'SET_COURSE'
]),
getData () {
this.$post(`${this.api.findByIdCourse}?id=${this.id}`).then(({ data }) => {
this.courseName = data.courseName
this.description = data.courseIntroduction
this.coverUrl = data.coverUrl || 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220224/png/1496735335294984192.png'
this.getChapter()
const path = this.$store.state.course.referrer
this.routes = [
{
name: '课程学习',
path
},
{
name: this.$route.query.source == 1 ? '本校课程' : '共享课程',
path
},
{
name: this.courseName
}
]
}).catch(res => { })
},
async getChapter () {
let res = await this.$get(`${this.api.queryChaptersAndSubsections}?courseId=${this.id}`)
this.chapterList = res.chapterList
if (this.chapterList.length && this.chapterList[0].subsectionList && this.chapterList[0].subsectionList.length) {
this.preview(this.chapterList[0].subsectionList[0], this.chapterList[0].name, 0);
}
},
insertScript () {
const linkTag = document.createElement('link');
linkTag.rel = 'stylesheet';
linkTag.href = 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css';
document.body.appendChild(linkTag);
const scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js';
document.body.appendChild(scriptTag);
},
transferType (ext) {
const suf = ext.toLowerCase()
if ('jpg,jpeg,png,gif,svg,psd'.includes(suf)) return '图片'
if ('mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv'.includes(suf)) return '视频'
return suf
},
preview (row, chapterName, showConfirm = 1) {
// 如果没登录,直接去登录
if (!util.session.get(Setting.tokenKey) && !util.local.get('oc_server_token') && showConfirm) {
this.$confirm('请先登录,是否直接前往登录?', "提示", {
type: 'success',
closeOnClickModal: false
}).then(() => {
this.SET_COURSE(this.id)
this.$router.push('/login')
}).catch(() => { })
return false
}
this.curLink = `${chapterName}${row.name}`;
this.playauth = ''
this.coverUrl = ''
this.pdfSrc = ''
this.iframeSrc = ''
this.isPPT = false
this.isWord = false
this.isExcel = false
if (this.transferType(row.fileType) == '视频') {
// 阿里云视频点播
if (row.fileId) {
this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => {
this.playAuth = res.playAuth
// 如果已经产生了实例,则销毁重新创建,不然播放器会播放上一个视频
if (this.player) {
this.player.dispose()
this.player = null
}
this.$nextTick(() => {
if (this.player) {
this.player.replayByVidAndPlayAuth(row.fileId, this.playAuth);
} else {
this.player = new Aliplayer({
id: "player",
width: "100%",
autoplay: false,
vid: row.fileId,
playauth: this.playAuth,
encryptType: 1 //当播放私有加密流时需要设置。
});
}
});
}).catch(res => { })
} else {
this.videoSrc = row.fileUrl
}
} else if (this.transferType(row.fileType) == '图片') {
this.coverUrl = row.fileUrl
} else if (row.fileType == 'pdf') {
this.pdfSrc = row.fileUrl
this.pdfVisible = true
} else {
this.$get(`${this.api.getSubsection}?subsectionId=${row.id}`).then(res => {
if (row.fileType == 'pptx') {
this.isPPT = true
this.isWord = false
this.isExcel = false
} else if (row.fileType == 'doc' || row.fileType == 'docx') {
this.isPPT = false
this.isWord = true
this.isExcel = false
} else if (row.fileType == 'xls' || row.fileType == 'xlsx') {
this.isExcel = true
this.isPPT = false
this.isWord = false
} else {
this.isPPT = false
this.isWord = false
this.isExcel = false
}
if (this.isPPT) {
this.showMask = true
} else {
this.showMask = false
}
if (this.isWord) {
this.showMask1 = true
} else {
this.showMask1 = false
}
if (this.isExcel) {
this.showMask2 = true
} else {
this.showMask2 = false
}
this.iframeSrc = res.previewUrl
})
.catch(err => {
});
}
},
closePlayer () {
this.playAuth = ''
this.player.pause()
},
closeIframe () {
this.iframeSrc = ''
this.showMask = false
this.showMask1 = false
},
closePdf () {
this.pdfSrc = ''
this.currentPage = 1
},
changePdfPage (val) {
if (val === 0 && this.currentPage > 1) {
this.currentPage--
}
if (val === 1 && this.currentPage < this.pageCount) {
this.currentPage++
}
},
loadPdfHandler (e) {
this.currentPage = 1
}
}
};
</script>
<style>
.desc img {
width: 100%;
}
</style>
<style lang="scss" scoped>
$height: 700px;
.video_wid,
.cover {
position: relative;
width: 76%;
height: $height !important;
border: 0;
}
.page {
margin: 12px 0;
.intro {
font-size: 16px;
color: #333;
line-height: 24px;
}
}
.cover {
flex: 1;
background-color: #252528;
img {
border-radius: 8px;
}
&.is-word {
overflow: hidden;
}
}
.fileIframe {
height: $height !important;
}
.video_wid,
.inner {
width: 100%;
height: 100% !important;
border: 0;
overflow: auto;
}
.cover.is-word {
.inner {
height: calc(100% + 38px) !important;
margin-top: -38px;
}
}
.video_wid:focus {
outline: none;
}
.catalog {
width: 296px;
padding: 16px;
margin-left: 12px;
background-color: #252528;
.entry {
display: block;
width: 100%;
height: 34px;
margin-bottom: 16px;
background: url(../../../assets/img/entry.png) 0 0/100% 100% no-repeat;
cursor: pointer;
&:hover {
opacity: 0.9;
}
}
}
.list {
height: calc(700px - 82px);
overflow-y: auto;
.title {
margin-bottom: 11px;
color: #fff;
font-size: 16px;
}
.desc-wrap {
position: relative;
.desc {
font-size: 12px;
color: #fff;
line-height: 22px;
@include mul-ellipsis(4);
&.active {
display: block;
overflow: visible;
}
}
.arrow {
position: absolute;
bottom: 2px;
right: 0;
display: flex;
justify-content: space-between;
width: 46px;
background-color: #fff;
span {
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
img {
width: 16px;
cursor: pointer;
}
&.active {
span {
opacity: 0;
}
img {
transform: rotate(180deg);
}
}
}
}
.chapters {
margin-top: 16px;
max-height: calc(100% - 53px);
overflow: auto;
}
.chapter {
margin-bottom: 20px;
.chapterName {
color: #fff;
font-size: 14px;
}
.section {
padding: 5px 15px;
margin-top: 12px;
background-color: #121214;
.sectionName {
margin: 12px 0;
font-size: 12px;
color: #999;
cursor: pointer;
@include ellipsis;
img {
margin-right: 8px;
}
&.active {
color: #fff;
}
}
}
}
}
.el-image-viewer__wrapper {
transform: translateY(-10px);
transition: transform 0.5s;
&.active {
transform: translateY(0);
}
}
.el-image-viewer__close {
z-index: 2000;
top: 15px;
right: 15px;
&.doc-close {
i {
color: #000 !important;
}
}
}
.list::-webkit-scrollbar {
width: 4px;
}
.list::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.06);
}
.mask {
z-index: 9;
position: absolute;
background-color: rgb(57, 58, 61);
}
.word-mask {
z-index: 9;
position: absolute;
top: 0;
right: 0;
width: 100%;
background-color: rgb(243, 242, 241);
}
.word-mask1 {
z-index: 9;
position: absolute;
top: 0;
right: 0;
width: 100%;
background-color: #185abd;
}
.word-mask2 {
z-index: 9;
position: absolute;
background-color: transparent;
}
.excel-mask1 {
z-index: 9;
position: absolute;
top: 0;
left: 20%;
width: 60%;
background-color: #107c41;
}
/deep/.pdf-dia {
border-radius: 0 !important;
.el-dialog__header {
display: none;
}
.el-dialog__body {
padding: 0;
}
.el-dialog__headerbtn {
top: 10px;
.el-dialog__close {
color: #fff;
font-size: 16px;
}
}
}
.pdf {
.arrow {
padding: 10px 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #fff;
background-color: #333;
.turn {
margin: 0 10px;
font-size: 18px;
cursor: pointer;
}
}
.pdf-wrap {
width: 80%;
margin: 0 auto;
}
}
/deep/.project-dia {
.el-dialog__body {
padding: 28px 32px;
}
}
.projects {
display: flex;
flex-wrap: wrap;
max-height: 400px;
overflow: auto;
li {
display: inline-flex;
align-items: center;
width: 238px;
padding: 16px;
margin: 0 20px 20px 0;
background-color: #f6f8fa;
border-radius: 16px;
cursor: pointer;
&:hover {
span {
color: #007eff;
}
}
&:nth-child(3n) {
margin-right: 0;
}
&.active {
background-color: #f2f7ff;
span {
color: #3988ff;
}
}
}
span {
max-width: 140px;
margin-left: 14px;
font-size: 14px;
color: #333;
}
}
@media (max-width: 1430px) {
.wrap {
padding: 12px 100px 20px;
}
}
</style>