Files
learning-system-mobile/pages/study/onlineCourse.vue
2022-05-30 23:03:25 +08:00

1566 lines
49 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><watermark></watermark>
<u-toast ref="messager"></u-toast>
<page-title :showBack="true">{{courseInfo.name}}</page-title>
<view>
<!--内容播放区-->
<view style="min-height: 400upx;" >
<view v-if="curContent.contentType==10" >
<!--视频-->
<view style="position: relative;">
<video id="myVideo"
@touchend="Double"
:src="fileBaseUrl+curriculumData.url"
controls
:enable-play-gesture="true"
:initial-time="curContent.lastStudyTime"
@play="onPlayerPlay"
@pause="onPlayerPause"
@ended="onPlayerEnded"
@timeupdate="onPlayerPlaying"
@fullscreenchange="onFullScreen"
style="width: 100%; object-fit: fill">
</video>
<!--倍速度-->
<view id="myVideoSpeed" class="player-controls-btn cursor-pointer btn-speed">
<view @click="showSpeedCtrl">{{videoSpeed === 1 ? '倍速' : `${videoSpeed}x`}}</view>
<view class="speed-control" v-if="speedListShow">
<view class="speed-control-list">
<view class="li"
v-for="item in speedList"
:key="item"
@click="changeSpeed(item)"
:data-value="item"
:class="{'current': videoSpeed === Number(item)}">
{{ item }}x
</view>
</view>
</view>
</view>
<view class="player-box" v-if="playerBoxShow">
<view class="player-praise">
<view @click="praiseContent" style="cursor: pointer;">
<image class="icon-small" v-if="isPraise" src="/static/images/icon/praise-active.png" />
<image class="icon-small" v-else src="/static/images/icon/praise1.png" />
<!-- {{ courseInfo.praises }} -->
<view style="color:#fff;cursor: pointer;"></view>
</view>
<view style="margin-left: 15px;cursor: pointer;" @click="treadContent">
<image class="icon-small" v-if="isTrample" src="/static/images/icon/trample-active.png" />
<image class="icon-small" v-else src="/static/images/icon/trample.png" />
<!-- {{ courseInfo.trampleCount }} -->
<view style="color:#fff;cursor: pointer;"></view>
</view>
</view>
<view v-if="!scoreInfo.has" class="player-rate">
<u-rate v-model="scoreInfo.score" active-color="#f7ba2a" text-color="#ff9900" score-template="{value}" void-color="#fff" @change="addScore"></u-rate>
</view>
<view v-if="scoreInfo.has" style="padding-top: 5px;display: flex;">
<view class="player-rate" style="padding-left: 5px;">
<!-- <u-rate active-color="#f7ba2a" readonly v-model="courseInfo.score" :allow-half="true" ></u-rate> -->
<u-rate readonly :count="5" active-color="#f7ba2a" v-model="scoreInfo.score"></u-rate>
</view>
<view class="score-text" style="margin-top:20px">
<text style="color:#ffb30f;">{{ toScore(scoreInfo.score) }}</text>
<text style="font-size: 12px;color: #fff"></text>
</view>
</view>
</view>
</view>
</view>
<!---->
<view v-if="curContent.contentType==20">
<!--音频播放-->
<view style="text-align: center;padding-top: 40px;background-color: #FFFFFF;">
<audio-player
:src="fileBaseUrl+curriculumData.url"
:name="curContent.contentName"
:drag="curriculumData.isDrag"
@onPlay="audioPlay"
@onPause="audioPause"
@onPlaying="audioPlaying"
@onEnded="audioEnd">
</audio-player>
</view>
</view>
<view v-if="curContent.contentType==30">
<image :src="fileBaseUrl+curContent.content" style="width: 100%;"></image>
</view>
<view v-if="curContent.contentType==40">
<!--pdf文档-->
<view style="min-height: 500px;padding-top: 200upx;position: relative;">
<pdf-preview v-if="curContent.content && curContent.content!=''" :src="curContent.content ? fileBaseUrl+curContent.content : ''"></pdf-preview>
</view>
</view>
<view v-if="curContent.contentType==41">
<view style="padding: 15px;text-indent:40px;line-height: 28px;position: relative;">
<u-parse :content="curContent.content"></u-parse>
</view>
</view>
<view v-if="curContent.contentType==52">
<!--外连接-->
<view v-if="conLink.url!=''" style="min-height: 400px;position: relative;">
<web-view :src="conLink.url"></web-view>
</view>
</view>
<!--作业-->
<view v-if="curContent.contentType==60">
<course-homework :content="curContent" :studyId="studyId"></course-homework>
</view>
<!--考试-->
<view v-if="curContent.contentType==61">
<course-exam :courseType="courseInfo.type" :content="curContent" :studyId="studyId"></course-exam>
</view>
<!--评估-->
<view v-if="curContent.contentType==62">
<course-assess :content="curContent" :studyId="studyId"></course-assess>
</view>
</view>
<!-- 评分赞和踩 -->
<u-popup :show="scoreInfo.dlgShow" mode="top" @close="closeScore" @open="openScore">
<view style="text-align: center;padding: 50upx;">
<view style="text-align: center;">给课程打分</view>
<view style="padding-top: 100upx;display: flex;justify-content: center;">
<u-rate :count="5" :size="25" v-model="scoreInfo.score"></u-rate>
</view>
<view style="padding-top: 100upx;height: 100upx;">
<u-button type="primary" @click="addScore()" text="提交评分"></u-button>
</view>
</view>
</u-popup>
<view class="main-footer">
<view>
<u-rate v-if="!scoreInfo.has" :count="5" :size="25" active-color="#f7ba2a" v-model="scoreInfo.score" @change="addScore()"></u-rate>
<u-rate v-else readonly :count="5" :size="25" active-color="#f7ba2a" v-model="scoreInfo.score"></u-rate>
<!-- <text v-if="!scoreInfo.has" @click="openScore()" class="main-scroe">去评分</text> -->
<!-- <text v-else style="color: #ffaa00;font-size: 32upx;">{{changeScore(scoreInfo.score)}} </text> -->
<!-- <u-rate class="star-rate" :disabled="true" activeColor="#FA3534" :allowHalf="true" v-show="isPraise" :count="5" :size="25" v-model="courseInfo.score"></u-rate> -->
</view>
<view style="display: flex;justify-content: flex-end;">
<view @click="praiseContent()">
<image :src="'/static/images/icon/'+(isPraise? 'praise-active.png':'praise1.png')" style="width:35upx;height: 35upx;margin-right: 5px;"></image> {{courseInfo.praises}}
</view>
<view @click="treadContent()">
<image :src="'/static/images/icon/'+(isTrample? 'trample-active.png':'trample.png')" style="width:35upx;height: 35upx;margin-left: 30upx;margin-right: 5px;"></image> {{ courseInfo.trampleCount }}
</view>
</view>
</view>
</view>
<!--内容切换-->
<view class="main-cata">
<view class="main-cata-top" >
<view style="font-size: 17px;">目录
<!-- <text style="color: #666666;font-size: 22rpx;">点击查看完整大纲</text> -->
</view>
<!-- <view style="margin-top: 10rpx;" @click="showOrHideCatalog"> -->
<!-- <u-icon v-if="!catalogShow" name="arrow-down" color="#b3b3b3" size="16"></u-icon>
<u-icon v-if="catalogShow" name="arrow-up" color="#b3b3b3" size="16"></u-icon> -->
<!-- </view> -->
<!-- <text style="color: #666;font-size: 22rpx;margin-top: 8rpx;">点击查看完整大纲</text> -->
<!-- <view class="course-xiang" @click="showSummarylog">
课程详情
</view> -->
<view style="display: flex;font-size: 28rpx;color: #666666;" @click="showOrHideCatalog">
<view style="line-height: 46rpx;">
全部
</view>
<u-icon style="" name="arrow-right"></u-icon>
</view>
</view>
<view v-if="scrollItemWidth>0" class="main-cata-active">
<scroll-view scroll-x :scroll-y="false" style="height:115px;white-space: nowrap;overflow: hidden;" :scroll-left="scrollInfo.scrollLeft" @scrolltoupper="scrollLeft" @scrolltolower="scrollRight" @scroll="scrollHandler">
<!-- <view class="mycrollcontent" style="display: flex;justify-content:flex-start;"> -->
<view v-for="(con,conIdx) in scrollList" :key="conIdx" style="display: inline-block;" :id="con.id" @click="playContent(con.cataName,con,conIdx,0)">
<!---->
<view :style="{width:scrollItemWidth+'px'}" class="scroll-item" :class="{'studying':curContent.id==con.id}">
<view class="scroll-item-sec">{{con.cataName}}
<!-- <text v-if="con.cataStatus && con.cataStatus==1" class="status-tag" :class="statusClass(con.cataStatus)">未开始</text>
<text v-if="con.cataStatus && con.cataStatus==2" class="status-tag" :class="statusClass(con.cataStatus)">进行中</text>
<text v-if="con.cataStatus && con.cataStatus==9" class="status-tag" :class="statusClass(con.cataStatus)">已完成</text> -->
</view>
<view class="scroll-item-con">
<view class="scroll-item-name">
{{con.contentName}}
</view>
<!-- <view class="scroll-item-type">
<view class="square-border">
<view :class="statusClass(con.status)">
{{getConType(con.contentType)}}
</view>
</view>
<text v-if="con.status==1" class="status-tag" :class="statusClass(con.status)">未开始</text>
<text v-if="con.status==2" class="status-tag" :class="statusClass(con.status)">进行中</text>
<text v-if="con.status==9" class="status-tag" :class="statusClass(con.status)">已完成</text>
</view> -->
</view>
</view>
</view>
<!-- </view> -->
</scroll-view>
<!-- <view style="padding:15upx 20upx 10upx 0upx; display: flex;justify-content: space-between;">
<view>{{curSection.name}}</view>
<view>
<text v-if="curSection.status==0" class="status-tag nostart">未开始</text>
<text v-if="curSection.status==1" class="status-tag studying">进行中</text>
<text v-if="curSection.status==9" class="status-tag finish">已完成</text>
</view>
</view>
<view :class="statusClass" style="padding:15upx 20upx 10upx 40upx; display: flex;justify-content: space-between;">
<view>{{curContent.contentName}}</view>
<view>
<text v-if="curContent.status==0" class="status-tag nostart">未开始</text>
<text v-if="curContent.status==1" class="status-tag studying">进行中</text>
<text v-if="curContent.status==9" class="status-tag finish">已完成</text>
</view>
</view> -->
</view>
</view>
<!--评论-->
<view>
<comments ref="comments" v-if="courseId && courseId!=''" :objType="1" :objId="courseId"></comments>
</view>
<!--底部-->
<interact-fixed :type="1" :data="courseInfo" :users="teachers" :praises="false" :comments="false" @comment-success="refreshComments" @share-success="shareSuccess"></interact-fixed>
<u-popup :show="catalogShow" mode="right" @close="closeCatalog" :safeAreaInsetTop="true" :closeable="true">
<view :style="`width: ${treePopupWidth};padding-top: 20px;`" style="height: 100vh; overflow: auto;">
<view class="" style="padding: 5px 9px;color:#2d2d2d;font-weight: bold;margin-bottom: 20rpx;">
目录
</view>
<view class="catalog">
<view v-for="(cata,catIdx) in catalogTree" :key="catIdx" style="border-bottom: 1px solid #ebebeb;margin-bottom: 50rpx;padding-bottom: 30upx;">
<view class="catalog-sec" style="margin-bottom: 20rpx;">
<view class="catalog-sec-name" >
<!-- <text>{{catIdx+1}}, </text> -->
<text class="text-ellipsis">{{cata.section.name}}</text>
</view>
<view>
<text v-if="cata.section.status==1" class="status-tag tag-nostart" style="font-size: 14px;">未开始</text>
<text v-if="cata.section.status==2" class="status-tag tag-studying" style="font-size: 14px;">进行中</text>
<text v-if="cata.section.status==9" class="status-tag tag-finish" style="font-size: 14px;">已完成</text>
</view>
</view>
<view >
<view v-for="(con,conIdx) in cata.children" :key="conIdx" class="catalog-con" @click="playContent(cata.section,con,conIdx,catIdx)">
<view class="catalog-con-name" :class="{'studying':curContent.id==con.id}">
<!-- <text>{{catIdx+1}}.{{conIdx+1}}, </text> -->
<!-- <text class="square-border">{{getConType(con.contentType)}}</text> -->
<text class="text-ellipsis" style="font-size: 14px;">{{con.contentName}}</text>
</view>
<view>
<text v-if="con.status==1" class="status-tag tag-nostart" style="font-size: 14px;">未开始</text>
<text v-if="con.status==2" class="status-tag tag-studying" style="font-size: 14px;">进行中</text>
<text v-if="con.status==9" class="status-tag tag-finish" style="font-size: 14px;">已完成</text>
</view>
</view>
</view>
</view>
</view>
<view style="height: 50px;"></view>
</view>
</u-popup>
<u-popup :show="summarylogShow" mode="right" @close="summaryCatalog" :safeAreaInsetTop="true" :closeable="true">
<view class="summary-log" :style="`width: ${treePopupWidth};padding-top: 20px;`" style="height: 100vh; overflow: auto;">
<!-- <view class=""> -->
<view class="particulars">课程详情</view>
<view class="matter">
<u-parse v-if="courseInfo.summary" :content="courseInfo.summary"></u-parse>
<text v-else>暂无</text>
</view>
<!-- </view> -->
</view>
</u-popup>
</view>
</template>
<script>
import apiCoursePortal from '@/api/modules/coursePortal.js'
import apiCourseStudy from '@/api/modules/courseStudy.js'
import apiVideoStudy from "@/api/modules/videoStudy.js";
import apiCourseGrade from "@/api/modules/courseGrade.js";
import apiCourseFile from "@/api/modules/courseFile.js";
import apiUser from '@/api/system/user.js'
import apiResOwner from '@/api/modules/resowner.js'
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import {getContentType} from "@/utils/tools.js";
import studyUtil from '@/utils/study.js';
import {toScore} from '@/utils/tools.js';
import { mapGetters } from 'vuex'
export default {
components:{},
data() {
return {
isPlaying:false,
onplay:false,
touchNum : 0,
playerBoxShow:false,
toScore:toScore,
summarylogShow: false,
scrollItemWidth:this.$width,
treePopupWidth:'400px',
fileBaseUrl:this.$config.fileUrl,
getConType:getContentType,
courseId:'',//当前课程的id
studyId: '',//当前学习的id
initContentId:'',//初始化的内容id
curSection:{},//当前所在的章
curContent:{
studyItemId:'',
status:1
},//当前的内容
conLink:{openType:1,url:''},//外连接内容
curriculumData:{url:'',isDrag:true,completeSetup:1,setupTage:0,second:0},// 课件内容
courseInfo:{id:'',name:''},//课程信息
totalContent:0,//课程内容数量
authorInfo:{aid:'',name:'',code:'',orgInfo:''},
teachers:[],
sectionList:[],
contentList:[],
videoScore:3,
videoPlayer:null,
videoPlayingTime:0,
speedListShow:false,
speedList:["2.0", "1.5", "1.25", "1.0", "0.75", "0.5"],
videoSpeed: 1.0, // 当前倍速:
tabIndex:0,
catalogShow:false,//是否显示目录
scoreInfo:{
dlgShow:false,
score:5,
has:false,
},
isPraise:false,
isTrample:false,
interactRuning:false,
scrollInfo:{
scrollLeft: 0,
scrollWidth: 0
},
handleTimeout:null,
isAppendTime:true,
appendStartTime: null, //记录追加的开始时间
appendHandle:null,
appentId:'',//当前追加的学习时长的id
appentInterval:30000,//追加学习时间的间隔 30秒加一次
preTime:-1
}
},
onLoad(options) {
//this.$watermark.set(this.userInfo.name+ this.userInfo.loginName);
this.scrollItemWidth=(this.$width-100)/2;//横向滚动的内容块宽度
this.treePopupWidth=(this.$width-100)+'px'; //右边出来的抽屉宽度控制
if(options.contentId){
this.initContentId=options.contentId;
}
this.courseId=options.id;
this.studyId=options.studyId;
this.loadDetail();
},
onShow(){
uni.setNavigationBarTitle({ title:'\u200E' })
//实时渲染当前的播放状态
},
onReady() {
this.videoPlayer=uni.createVideoContext("myVideo", this);
},
computed:{
...mapGetters(['userInfo']),
catalogTree(){
let treeList=[];
let $this=this;
$this.sectionList.forEach(sec=>{
let treeNode={section:sec,children:[]}
sec.status = 1;
let finishCount = 0;
$this.contentList.forEach(c=>{
if (c.csectionId == sec.id) {
if (c.status > 1) {
sec.status = 2;
if(c.status == 9){
finishCount++;
}
}
treeNode.children.push(c);
}
});
if (finishCount == treeNode.children.length) {
sec.status = 9;
}
treeList.push(treeNode);
})
return treeList;
},
scrollList(){
let list=[];
this.catalogTree.forEach((cata)=>{
cata.children.forEach((child,childIdx)=>{
if(childIdx==0){
child.cataName=cata.section.name;
child.cataStatus=cata.section.status;
}else{
child.cataName='';
}
list.push(child)
})
});
return list;
},
},
methods: {
Double(e){
// this.onPlayerPause()
this.touchNum ++
setTimeout(()=>{
if(this.touchNum == 1){
// console.log('单击')
}else if(this.touchNum >= 2){
if(this.isPlaying){
this.onPlayerPause()
} else {
this.onPlayerPlay()
}
}
this.touchNum = 0
},250)
},
changeScore(score){
if(!score){
return '0.0'
}
score=String(score)
if(score.indexOf('.')!=-1){
score=score.toFixed(1)
}else{
score=score+'.0'
}
return score
},
scrollLeft(e){
//console.log(e);
//this.scrollInfo.scrollLeft = 0
},
scrollRight(e){
//console.log(e);
//this.scrollLeft=e.detail.scrollLeft;
},
scrollHandler(e) {
//console.log(e);
this.scrollInfo = e.detail;
},
loadDetail(){
let $this=this;
uni.showLoading({title:'加载中...'})
apiCoursePortal.detail(this.courseId).then(rs=>{
setTimeout(function(){uni.hideLoading()},1000);
if(rs.status==200){
// uni.setNavigationBarTitle({ title:rs.result.course.name })
this.courseInfo=rs.result.course;
this.teachers=rs.result.teachers;
if(rs.result.teachers && rs.result.teachers.length > 0) {
let userIds = [];
let ctoUsers = [];
rs.result.teachers.forEach(item => {
// item.aid='';
item.name= '';
item.orgInfo= '';
item.avatar= '';
item.code= '';
item.sex=null;
userIds.push(item.teacherId);
ctoUsers.push({ aid: item.teacherId, name: item.teacherName });
});
// this.toUsers = ctoUsers;
this.loadAuthorInfo(rs.result.teachers, userIds);
}
this.loadUserInfo(this.courseInfo.sysCreateAid);
//设置必须的字段
let showConId=this.initContentId;
rs.result.sections.forEach(sec=>{
sec.status=1;//加入状态表未开始
rs.result.contents.forEach(c=>{
c.status=1;//初始化状态 ,未开始
c.studyItemId='';//初始化字段学习条目id
c.lastStudyTime=0;
if(showConId!='' && c.id==showConId){
$this.curContent=c;
$this.curSection=sec;
}
});
})
this.contentList=rs.result.contents;
this.totalContent=rs.result.contents.length;
this.sectionList=rs.result.sections;
//设置正在学习的章节
if(showConId==''){
this.curContent=this.contentList[0];
this.curSection=this.sectionList[0];
//要不要在这里处理?
if(this.curContent.contentType==10 || this.curContent.contentType==20){
if(this.contentList[0].content.startsWith('\{')){
this.curriculumData=JSON.parse(this.contentList[0].content);
}else{
this.curriculumData.url=this.contentList[0].content;
}
}
}
//study info
this.loadStudyInfo();
}else{
this.$refs.messager.show({message:rs.message,type:'error'});
}
})
},
loadAuthorInfo(list, ids) {
//加载作者信息,头像,机构信息
if (ids.length == 0) {
return;
}
apiUser.getByIds(ids).then(res => {
if (res.status == 200) {
list.forEach((item, index) => {
res.result.some(author => {
if (author.aid == item.teacherId) {
// item.authorInfo = author;
// item.aid=author;
item.name= author.name;
item.orgInfo= author.orgInfo;
item.avatar= author.avatar;
item.code= author.code;
item.sex=author.sex;
if(author.avatar != '') {
item.avatar=this.$config.fileUrl + author.avatar;
}
return true;
} else {
return false;
}
});
});
} else {
//console.log('加载课程信息失败:'+res.error);
//this.$message.error(res.message);
}
});
},
loadStudyInfo() {
//获取学习信息
let $this = this;
apiCourseStudy.studyInfo(this.courseId).then(res=>{
if(res.status == 200) {
if(res.result.signup){
this.loadScorePraiseAndTrample();
this.studyId = res.result.studyId;
//对已学习的内容进行比对,重要的字段, 学习内容id在后缀的
this.contentList.forEach(con=>{
res.result.contents.forEach((scon,sconIdx)=>{
//第一条就是最近学习的
if(sconIdx==0 && $this.initContentId==''){
//$this.curContent=con;
//查询对应的章节
}
if(scon.contentId==con.id){
con.lastStudyTime = scon.lastStudyTime;
//以下判断是为了兼容之前的问题,学习状态
if(scon.status){
con.status = scon.status;
}else{
con.status = 9;
}
con.studyItemId=scon.id;//这个就是学习内容条目的id
}
})
});
}
} else {
this.$refs.messager.show({message:res.message,type:'error'});
}
})
},
loadUserInfo(uid){
apiUser.getByIds([uid]).then(res=>{
if(res.status==200){
this.authorInfo=res.result[0];
}
})
},
saveStudyItem(){ //先保存学习的内容,针对于音视频的内容
if(this.curContent.studyItemId) {
return;//已经有记录的,不需要再保存了
}
let params = {
studyId: this.studyId, //学习id,
courseId: this.courseId, //课程id,
contentId: this.curContent.id, //内容id,
contentType:this.curContent.contentType, //内容id,
contentName: this.curContent.contentName, //内容名称
progress: 0,
lastStudyTime:0,
status:2,
studyDuration:0,
contentTotal: this.totalContent
};
apiVideoStudy.saveStudyItem(params).then(res=>{
if(res.status == 200){
this.curContent.studyItemId=res.result.id;
this.curContent.status = 2;//进行中状态
}else{
console.log("记录学习失败:" + res.message + "" + res.error);
}
});
},
finishStudyItem(){ //设置完成学习的内容,针对于音视频的内容
if(!this.curContent.studyItemId){
//这种可能没有不过这里也是为了万中那个1
this.saveStudyInfo();
}else{
let params={
itemId:this.curContent.studyItemId,
studyId:this.studyId,
courseId:this.courseId,
cnum:this.totalContent
}
apiVideoStudy.finishStudyItem(params).then(res=>{
if(res.status == 200){
this.curContent.status = 9;
this.curContent.progress = 100;
}else{
console.log("记录完成学习失败:" + res.message + "" + res.error);
}
});
}
},
onFullScreen(e){
//console.log(e,'e');
let full=e.detail.fullScreen;
let divId='videowatermark';
setTimeout(() => {
var div = document.getElementById('myVideo')
var div1 = div.firstChild;
var speedDiv=div1.querySelector("#myVideoSpeed");
if(full){
var div3 = document.createElement("div");
div3.id =divId;
div3.setAttribute("class", "fullmark");
div3.innerHTML='';
// 从父组件传过来的水印内容
//div3.innerText =this.userInfo.name+this.userInfo.code;
for(var i=0;i<4;i++){
div3.innerHTML+='<div style="color:#ffffff;width: 40%;height: 155px;padding-left:60px;padding-top:50px; display: flex;justify-content: center; transform: rotate(-36deg);font-size:20px;">'+this.userInfo.name+this.userInfo.code+'</div>';
}
div3.style.cssText = "position:absolute;pointer-events: none; width: 100%;height: 100%;top:0;left:0;bottom: 0;right: 0; display: flex;justify-content: center;flex-wrap: wrap;overflow: hidden; opacity:0.3;padding-top:10px";
//console.log(div3,'div3');
div1.appendChild(div3);
if(!speedDiv){
var speedDiv=document.getElementById('myVideoSpeed');
div1.appendChild(speedDiv)
}
}else{
var markDiv=div1.querySelector("#"+divId);
//var speedDiv=div1.querySelector("#myVideoSpeed");
if(markDiv){
div1.removeChild(markDiv);
}
if(speedDiv){
//div1.removeChild(speedDiv);
}
}
}, 200);
},
onPlayerPlay(){
this.isPlaying = true;
this.videoPlayingTime=0;
// console.log("开始播放");
this.playerBoxShow=false;
this.isAppendTime=false;
this.videoSpeed=studyUtil.getVideoSpeed();
this.videoPlayer.playbackRate(this.videoSpeed);
this.videoPlayer.play();
let $this=this;
if(this.curContent.status<9){
let completeType=this.curriculumData.completeSetup;
//console.log(completeType,'completeType');
if(completeType==0){
//默认5秒后学习完成.
$this.handleTimeout= setTimeout(function() {$this.saveStudyInfo();}, 5000); //5秒后记录学习完成
}else{
//先记录进行中的学习内容
this.saveStudyItem();
}
}
},
onPlayerPause(){
this.isPlaying = false;
this.videoPlayer.pause();
},
onPlayerEnded(){
this.playerBoxShow=true;
//console.log("播放结束");
//this.isAppendTime=true;//开启追
//加学习时间
if(this.curContent.status<9){
this.finishStudyItem();
}
},
changeSpeed(e) {
// 获取选择的倍速
let value = e;
this.videoSpeed = Number(value);
this.videoPlayer.playbackRate(this.videoSpeed);
studyUtil.setVideoSpeed(this.videoSpeed);
this.speedListShow=false;
},
showSpeedCtrl(){
if(this.speedListShow){
this.speedListShow=false;
}else{
this.speedListShow=true;
}
},
formatSeconds(a) {
var hh = parseInt(a/3600);
var mm = parseInt((a-hh*3600)/60);
if(mm<10) mm = "0" + mm;
var ss = parseInt((a-hh*3600)%60);
if(ss<10) ss = "0" + ss;
if(hh<10) hh = hh == 0?'':`0${hh}:`;
var length = hh + mm + ":" + ss;
if(a>=0){
return length;
}else{
return "00:00";
}
},
onPlayerPlaying(e){
//console.log("当前播放11",itme);
this.isAppendTime=false;//禁止追加学习时间
//console.log("当前播放11"+itme);
let intTime=parseInt(e.detail.currentTime);
if(intTime>this.videoPlayingTime){
this.videoPlayingTime=intTime;
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond){
completeSecond=5;//如果没有就采用默认的时间了
}
if(completeType>0 && this.curContent.status<9){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let videDuration=this.curContent.duration;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else if(completeType==2){
if(intTime>=completeSecond){
this.finishStudyItem();
}
}
}
}
//以下是每隔10秒存储一下进度
let saveTime=Math.floor(intTime%10);
//console.log(intTime,saveTime,'aa',this.curContent.studyItemId)
if(this.preTime!=intTime && saveTime==0 && this.curContent.studyItemId!=''){
this.preTime=intTime;
this.curContent.lastStudyTime=intTime;
//记录播放时间
//console.log('记录播放时间:'+intTime);
let postData={
itemId:this.curContent.studyItemId,
videoTime:intTime
}
apiCourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
audioPlay(){
this.isAppendTime=false;
let $this=this;
if(this.curContent.status<9){
let completeType=this.curriculumData.completeSetup;
//console.log(completeType,'completeType');
if(completeType==0){
//默认5秒后学习完成.
$this.handleTimeout= setTimeout(function() {$this.saveStudyInfo();}, 5000); //5秒后记录学习完成
}else{
//先记录进行中的学习内容
this.saveStudyItem();
}
}
},
audioEnd(){
if(this.curContent.status<9){
this.finishStudyItem();
}
},
audioPause(){
},
audioPlaying(e,second){
this.isAppendTime=false;//禁止追加学习时间
let intTime=second;//当前播放时间
let videDuration=e.duration;//音频总时长,秒
if(!videDuration){
videDuration=this.curContent.duration;
}
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond){
completeSecond=5;//如果没有就采用默认的时间了
}
if(completeType>0 && this.curContent.status<9){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else if(completeType==2){
if(intTime>=completeSecond){
this.finishStudyItem();
}
}
}
//以下是每隔10秒存储一下进度
let saveTime=Math.floor(intTime%10);
//console.log(intTime,saveTime,'aa',this.curContent.studyItemId)
if(this.preTime!=intTime && saveTime==0 && this.curContent.studyItemId!=''){
this.preTime=intTime;
this.curContent.lastStudyTime=intTime;
//记录播放时间
//console.log('记录播放时间:'+intTime);
let postData={
itemId:this.curContent.studyItemId,
videoTime:intTime
}
apiCourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
//还需要记录播放时间
saveStudyInfo() { //记录课件学习信息
if(this.curContent.contentType>=60){
//只有在课件页面停留超过5秒才会记录
return;
}
if(this.curContent.status==9){
//已学习完的,不用再添加
return;
}
let params ={
studyId: this.studyId,//学习id,
courseId: this.courseId,//课程id,
contentId: this.curContent.id,//内容id,
contentName: this.curContent.contentName,//内容名称
progress: 100,
contentTotal:this.totalContent
}
apiCourseStudy.studyContent(params).then(res=>{
if(res.status == 200) {
this.curContent.status=9;//完成
this.curContent.studyItemId=res.result;//学习记录id
}else{
console.log('记录学习失败:'+res.message+''+res.error);
}
})
},
loadScorePraiseAndTrample(){
//加载是否请过分
apiCourseGrade.has(this.courseId).then(rs=>{
if(rs.status==200 && rs.result){
this.scoreInfo.has=true;
}
});
apiPraises.has(1,this.courseId).then(rs=>{
if(rs.status==200 && rs.result){
this.isPraise=true;
}
});
apiTrample.has(this.courseId).then(rs=>{
if(rs.status==200 && rs.result){
this.isTrample=true;
}
});
},
closeScore(){
this.scoreInfo.dlgShow=false;
},
openScore(){
if(this.scoreInfo.has){
this.$refs.messager.show({message:'您已评过分',type:'error'});
return;
}
this.scoreInfo.dlgShow=true;
},
addScore(){
if(this.scoreInfo.has){
this.$refs.messager.show({message:'您已评过分',type:'error'});
this.scoreInfo.dlgShow=false;
return;
}
let postData={
courseId:this.courseInfo.id,
studyId:this.studyId,
score:this.scoreInfo.score
}
if(this.scoreInfo.score>0){
apiCourseGrade.grade(postData).then(rs=>{
if(rs.status==200){
this.scoreInfo.dlgShow=false;
this.scoreInfo.has=true;
this.$refs.messager.show({message:'评分成功谢谢您的评分',type:'success'});
}else{
this.$refs.messager.show({message:'评分分处理失败请稍后再试',type:'error'});
}
});
}
},
praiseContent(){
//赞和踩只能是一个
if(this.isTrample){
this.$refs.messager.show({message:'已踩不能赞了',type:'error'});
return;
}
let postData={
objType:1,
objId:this.courseInfo.id,
title:this.courseInfo.name
}
if(this.interactRuning){
return;
}
this.interactRuning=true;
if(this.isPraise){
apiPraises.remove(1,this.courseInfo.id).then(rs=>{
this.interactRuning=false;
if(rs.status==200){
this.$refs.messager.show({message:'已取消点赞',type:'success'});
this.isPraise=false;
this.courseInfo.praises--;
}else{
this.$refs.messager.show({message:'取消点赞失败,请稍后再试',type:'success'});
}
})
}else{
apiPraises.save(postData).then(rs=>{
this.interactRuning=false;
if(rs.status==200){
this.$refs.messager.show({message:'点赞成功',type:'success'});
this.isPraise=true;
this.courseInfo.praises++;
}else{
this.$refs.messager.show({message:'点赞失败,请稍后再试',type:'success'});
}
})
}
},
treadContent(){
//赞和踩只能是一个
if(this.isPraise){
this.$refs.messager.show({message:'已赞不能踩了',type:'error'});
return;
}
if(this.interactRuning){
return;
}
this.interactRuning=true;
if(this.isTrample){
//取消
apiTrample.remove(this.courseInfo.id).then(rs=>{
this.interactRuning=false;
if(rs.status==200){
this.$refs.messager.show({message:'已取消踩',type:'success'});
this.isTrample=false;
this.courseInfo.trampleCount--;
}else{
this.$refs.messager.show({message:'取消踩失败,请稍后再试',type:'error'});
}
})
}else{
apiTrample.trample(this.courseInfo.id).then(rs=>{
this.interactRuning=false;
if(rs.status==200){
this.$refs.messager.show({message:'已踩',type:'success'});
this.isTrample=true;
this.courseInfo.trampleCount++;
}else{
this.$refs.messager.show({message:'踩失败,请稍后再试',type:'error'});
}
})
}
},
showOrHideCatalog(){
this.catalogShow=!this.catalogShow
},
showSummarylog() {
this.summarylogShow=!this.summarylogShow
},
closeCatalog(){
this.catalogShow=false;
},
summaryCatalog() {
this.summarylogShow=false;
},
playContent(cata,con,conIndex,catIndex){
if(conIndex!=undefined && catIndex!=undefined) {
if(this.courseInfo.orderStudy) {
let hasIndex=-1;
this.scrollList.some((one,idx)=>{
if(one.id==con.id){
hasIndex=idx;
return true;
}
return false;
})
if(hasIndex>0){
let pre=this.scrollList[hasIndex-1];
if(pre.status!=9){
this.$refs.messager.show({message:'请按顺序学习',type:'error'});
return;
}
}
}
}
// console.log(con,'con');
if(this.videoPlayer){
//console.log('切换视频');
this.videoPlayer.stop();
}
this.playerBoxShow=false;
if(con.contentType==40){
//如果是文档需要再次加载pdf
if(con.content!='' && con.content.indexOf('.pdf')==-1){
// 先置空,否则会有延迟
con.content = '';
apiCourseFile.detail(con.contentRefId).then(cfrs=>{
if(cfrs.status==200){
con.content=cfrs.result.previewFilePath;
//console.log(r.content);
}else{
$this.$refs.messager.show({message:'加载pdf课件文件失败',type:'error'});
}
});
}
}else if(con.contentType==52){
if(con.content.startsWith('\{')){
this.conLink=JSON.parse(con.content);
}else{
this.conLink.url=con.content;
this.conLink.openType=1;
}
} else if(con.contentType==10 || con.contentType==20) {
if(con.content.startsWith('\{')){
this.curriculumData=JSON.parse(con.content);
}else{
this.curriculumData.url=con.content;
}
}
//this.curSection=cata;
this.curContent=con;
this.catalogShow=false;
this.scoreInfo.itemId=con.id;
if(this.curContent.status<2){
this.curContent.status=2; //设置状态 进行中
}
//横向滚动条定位
let len=0;
this.scrollList.some((sitem,idx)=>{
if(sitem.id==con.id){
len=idx;
return true;
}
return false;
})
this.scrollInfo.scrollLeft=len*this.scrollItemWidth+len*6;
if(con.contentType>20){
let $this=this;
//非视频音频的5秒后学习完成
this.handleTimeout = setTimeout(function(){$this.saveStudyInfo();},5000);
}
},
openComment(){
//打开评论窗口,调用组件内事件
this.$refs.fiexdbar.openInput();
},
refreshComments(){
this.$refs.comments.loadData(false);
},
openShare(){
this.$refs.fiexdbar.addShare();
},
shareSuccess(rs){
this.$refs.messager.show({message:'分享成功',type:'success'});
},
openCatalog(){
this.catalogShow=true;
//同时暂停视频播放
},
closeCatalog(){
this.catalogShow=false;
//同时启动视频播放
},
statusClass(status){
let statusObj={
1:'nostart',
2:'studying',
9:'finish',
}
return statusObj[status]
}
}
}
</script>
<style lang="scss" scoped>
.player-box{
position: absolute;
// top: 62px;
// left: 184px;
width: 200px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
height: 147px;
background:#a9abb3;
border-radius: 33px;
text-align: center;
padding: 20px;
box-sizing: border-box;
image{
width: 40px;
height: 40px;
margin: 0px 10px;
}
.player-praise{
margin-top: 5px;
display: flex;
// justify-items: center;
justify-content: center;
}
.player-rate{
margin-top: 20px;
text-align: center;
display: flex;
justify-content: center;
}
}
/deep/ .u-popup__content{
border-radius: 17px 0 0rpx 17px;
}
/deep/ .u-popup__content__close--top-right{
.u-icon__icon{
top: 10px !important;
}
}
.summary-log{
padding: 20rpx;
.particulars{
font-size: 32upx;
color: #666666;
margin-bottom: 20upx;
}
}
.star-rate>>>.uicon-star-fill {
color: rgb(230, 50, 50) !important
}
.player-controls-btn {
position: absolute;
right: 10px;
top: 10px;
display: inline-block;
color: #e5e5e5;
padding: 0 0.4rem;
transition: color 0.3s;
height: 22px;
}
.btn-speed:hover .speed-control {
// visibility: visible;
}
.speed-control {
position: absolute;
top: 180px;
right: -20px;
transition: visibility 0.3s;
transform: translate(-50%, -100%);
}
.speed-control .speed-control-list {
list-style: none;
color: #e5e5e5;
width: 50px;
font-size: 12px;
text-align: left;
padding: 0px 0px 0px 5px;
margin: 0;
overflow: hidden;
border-radius: 4px;
background: rgba(21, 21, 21, 0.8);
}
.speed-control .speed-control-list .li {
position: relative;
display: block;
height: 25px;
line-height: 25px;
}
.speed-control .speed-control-list .li:hover {
color: #fff;
background: rgba(99, 99, 99, 0.8);
}
.speed-control .speed-control-list .li.current {
color: var(--primaryColor);
}
.studying{
//正在学习的字体样式
// color: #2c7eb6;
color: #588AFC;
}
.scroll-item{
// height: 125px;
margin: 3px;
.scroll-item-sec{
height: 20px;
// padding: 10upx;
margin-bottom: 30upx;
margin-right: 20upx;
// word-wrap: break-word;
// word-break:break-all;
overflow: hidden;
text-overflow:ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1
}
.scroll-item-con{
width: 220rpx;
display:inline-flex;
border-radius: 8upx;
padding: 20upx;
// height: 60rpx;
// line-height: 60rpx;
background-color: #f4f5f7;
.scroll-item-name{
width: 100%;
height: 76rpx;
// white-space: pre-wrap;
word-break:break-all;
line-height: 40rpx;
overflow: hidden;
white-space: pre-wrap;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
display: -webkit-box;
-webkit-line-clamp: 2;
font-size: 28upx;
// margin-bottom: 20upx;
}
.scroll-item-type{
font-size: 26upx;
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 1;
.square-border{
margin-right: 20upx;
display: flex;
justify-content: center;
align-items: center;
border:1px solid;
padding: 3px 5px;
.finish{
padding: 5upx;
}
.nostart{
padding: 5upx;
}
}
>.studying{
background-color: #FDF1D7;
color:#FFB30F;
}
>.finish{
background-color: #BED2F8;
color: #3C7EFF;
}
>.nostart{
background-color: #FFC8C8;
color:#EE474A;
}
.status-tag{
width: 88upx;
height: 38upx;
line-height: 38upx;
}
}
}
.color-studying{
// background: #FDF1D7;
color: #FFB30F;
}
.color-finish{
// background: #f3f9ff;
color: #666666;
}
.color-nostart{
// background: #ffe8e7;
color: #666666;
}
}
.main-footer{
background-color: #FFFFFF;
padding: 30upx;
display: flex;
justify-content: space-between;
.main-scroe{
display: inline-block;
background-color: #ecf5ff;
font-size: 14px;
padding: 14upx 24upx;
border: 2rpx solid #409eff;
color: #409eff;
}
.main-praise{
}
}
.main-cata{
margin-top: 20upx;
.main-cata-top{
display: flex;
justify-content: space-between;
background-color: #FFFFFF;
padding: 30rpx 30rpx 10rpx 30rpx;
// border-bottom: 1px solid #ececec;
.course-xiang{
color: #a8a8a8;
// margin-left: 36%;/
}
}
.main-cata-active{
background-color: #FFFFFF;
padding: 0upx 20upx 10upx 20upx;
}
}
.active{
font-size: 24upx;
color: #ffaa00;
}
.tabbar{
height: 50px;
line-height: 50px;
background-color: #FFFFFF;
display: flex;
justify-content: space-around;
color: #575757;
.tabbar-item{
text-align: center;
line-height: 40px;
height: 40px;
}
.active{
border-bottom: 2px solid #00aaff;
color: #00aaff;
}
}
.toptitle{
display: flex;
justify-content: space-between;
line-height: 50upx;
border-bottom: 1px solid #e8e8e8;
padding: 5px 10px;
background-color: #FFFFFF;
.inner{
padding: 5px;
}
}
.tags{
padding-top: 20upx;
.tags-item{
display: inline-block;
border: 1px solid #007AFF;
padding: 8upx 20upx;
margin: 6upx;
color: #8b8b8b;
font-size: 20upx;
}
}
.text-row{
margin-top: 6upx;
color: #494949;
line-height: 30px;
font-size: 26upx;
.text-row-label{
font-weight: 600;
}
.text-row-value{
color: #007AFF;
}
}
.video-div{
position: absolute;
z-index: 999999999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #bcbcbc;
}
.paperinfo{
padding-top: 10px;
.paperinfo-title{
text-align: center;
font-size: 30upx;
font-weight: 600;
padding: 10px;
}
.paperinfo-item{
background-color: #FFFFFF;
}
}
.demand{
display: flex;
}
/deep/.content{
border-radius: 0px;
padding: 0;
padding-left: 10px;
padding-right: 10px;
padding-top: 10px;
margin-top: 0px;
.content-tit{
font-size: 14px;
margin-left: 10px;
}
.tags{
.tags-item{
display: inline-block;
background: #F6FAFD;
border-radius: 14px;
padding: 8upx 20upx;
color: #6D99FC;
font-size: 20upx;
}
}
.ziy{
font-size: 12px;
color: #666666;
margin-left: 12px;
margin-top: 3px;
}
.learning{
display: flex;
justify-content: space-between;
margin-left: 12px;
margin-top: 3px;
padding-bottom: 10px;
.learning-left{
font-size: 12px;
color: #666666;
}
.learning-right{
display: flex;
font-size: 16px;
color: #FFB30F;
margin-top: -8px;
.right-nav{
font-size: 12px;
color: #666666;
margin-top: 4px;
}
}
}
}
.status-tag{
height: 40upx;
width: 44px;
display: inline-block;
text-align: center;
line-height: 40upx;
padding: 2upx 10upx;
border-radius: 14upx;
}
.tag-studying{
// color: #FFB30F;
color: #588AFC;
}
.tag-finish{
// color: #00aaff;
color: #08A890;
}
.tag-nostart{
// color: #ff0000;
color: #787878;
}
.text-ellipsis{
//display: inline-block;
max-width: 80%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.catalog{
background: #FFFFFF;
padding:20upx;
.catalog-sec{
display: flex;
justify-content: space-between;
// border-bottom: 2upx solid #FAFAFA;
// padding:20upx;
line-height: 40upx;
.catalog-sec-name{
max-width: 90%;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.catalog-con{
display: flex;
justify-content: space-between;
padding:10upx;
padding-right: 0;
padding-left: 30rpx;
line-height: 40upx;
.square-border{
display: inline-block;
border:1px solid;
padding: 4upx 6upx;
font-size: 0.8em;
margin: 0upx 8upx;
}
.catalog-con-name{
padding-left: 0upx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
</style>