Files
learning-system-mobile/pages/study/courseStudy.vue
2022-11-13 23:17:19 +08:00

1574 lines
50 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 class="playbox"><!--内容播放区域-->
<view style="min-height: 500upx;" >
<view v-if="curContent.contentType==10" style="background-color: #000000;">
<!--视频-->
<view style="position: relative;">
<video id="myVideo"
@touchend="doubleClickVideo"
: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>
</view>
<view class="contentbox">
<view v-if="!catalogShow">
<view class="tabrow">
<view class="tabrow-item" @click="changeTab(1)"><text :class="{'tabrow-active':tabIndex==1}">简介</text></view>
<view class="tabrow-item" @click="changeTab(2)"><text :class="{'tabrow-active':tabIndex==2}">评论</text></view>
</view>
<!--简介内容-->
<view v-if="tabIndex==1" class="cinfo">
<view class="cinfo-title">
{{courseInfo.name}}
<text class="cinfo-tag1">通用力</text>
<text class="cinfo-tag2">职场技能</text>
</view>
<view class="desrow">
<view>
<text class="desrow-name">目标人群</text>
<text class="desrow-value">{{courseInfo.forUsers}}</text>
</view>
<view style="color: #999999;min-width: 160upx;text-align: right;">{{formatUserNumber(courseInfo.studys)}}人学习</view>
</view>
<view class="desrow" style="justify-content: flex-start;">
<view><text class="desrow-name">讲师</text></view>
<view style="flex: 1;">
<view v-for="tea in teachers" :key="tea.id" style="display: flex;justify-content: space-between;">
<view>
<text class="desrow-value">{{tea.teacherName}}</text>
<text class="desrow-value">({{tea.orgInfo}})</text>
</view>
<view @click="followUser(tea)" style="color: #387DF7;;">
<text v-if="tea.followed">已关注</text>
<text v-else>+关注</text>
</view>
</view>
</view>
</view>
<view class="desrow">
<view style="display: flex;">
<text class="desrow-name">课程评分</text>
<u-rate v-if="scoreInfo.score>0" :count="5" color="#FB7303" :size="16" v-model="scoreInfo.score"></u-rate>
<text class="score">{{toScore(scoreInfo.score)}}</text>
</view>
</view>
<view v-if="totalContent>1" class="desrow">
<view style="font-size: 32upx;color: #333333;">目录</view>
<view v-if="totalContent>2" @click="showAllCatalog" style="font-size: 28upx;color: #666666;">全部&gt;</view>
</view>
<view v-if="totalContent>1"><!--单个内容时不显示内容名称-->
<view v-if="totalContent==2">
<view v-if="courseInfo.type==10">
<view class="citembox1">
<view v-for="(con,conIdx) in contentList" :key="conIdx" class="citembox1-item">
<view class="citem" @click="playContent(con,conIdx,0)">
<view class="citem-body" :class="{'box-studying':con.id==curContent.id}">
<text :class="{'color-studying':con.id==curContent.id}">{{con.contentName}}</text>
</view>
</view>
</view>
</view>
</view>
<view v-else><!--有目录的但是只有两项内容-->
<view class="citembox1">
<view v-for="(con,conIdx) in scrollList" :key="conIdx" class="citembox1-item">
<view class="citem" @click="playContent(con,conIdx,0)">
<view class="citem-body" :class="{'box-studying':con.id==curContent.id}">
<text :class="{'color-studying':con.id==curContent.id}">{{con.contentName}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view v-else >
<view v-if="courseInfo.type==10">
<view v-if="scrollItemWidth>0" class="main-cata-active">
<scroll-view scroll-x :scroll-y="false" style="min-height:180upx;white-space: nowrap;overflow: hidden;" :scroll-left="scrollInfo.scrollLeft" @scroll="scrollHandler">
<!-- <view class="mycrollcontent" style="display: flex;justify-content:flex-start;"> -->
<view v-for="(con,conIdx) in contentList" :key="conIdx" style="display: inline-block;" :id="con.id" @click="playContent(con,conIdx,0)">
<!---->
<view :style="{width:scrollItemWidth+'px'}" class="scroll-item" :class="{'box-studying':curContent.id==con.id}">
<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>
</view>
<view v-else>
<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" @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,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>
</view>
</view>
</view>
<!--交互-->
<view class="cinfo-btns">
<view class="cinfo-btn" @click="openScore()">
<view><image src="/static/images/course/c_comment.png" style="width: 80upx;height: 80upx;"></image> </view>
<view>评价</view>
</view>
<view class="cinfo-btn" @click="addFavorite()">
<view>
<image v-if="isFavorite" src="/static/images/course/c_favorite_2.png" style="width: 80upx;height: 80upx;">
<image v-else src="/static/images/course/c_favorite.png" style="width: 80upx;height: 80upx;">
</view>
<view>收藏</view>
</view>
<view class="cinfo-btn" @click="openShare()">
<view>
<image src="/static/images/course/c_share.png" style="width: 80upx;height: 80upx;">
</view>
<view>转发</view>
</view>
</view>
</view>
<!--评论-->
<view v-show="tabIndex==2" class="pinglun">
<comments ref="comments" v-if="courseId && courseId!=''" :objType="1" :objId="courseId"></comments>
<interact-fixed ref="fiexdbar" :type="1" :data="courseInfo" :users="teachers" :praises="false" :comments="false" @comment-success="refreshComments" @share-success="shareSuccess"></interact-fixed>
</view>
</view>
<!--全部目录-->
<view v-else >
<view class="tabrow" style="justify-content: space-between;">
<view class="tabrow-item"><text class="tabrow-active">目录</text></view>
<view @click="closeAllCatalog"><text style="font-size: 32upx;">×</text></view>
</view>
<view class="catalogbox">
<view v-if="courseInfo.type>10" class="catalog">
<view v-for="(cata,catIdx) in catalogTree" :key="catIdx" style="border-bottom: 1px solid #ebebeb;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 :class="{'color-studying':cata.section.status==2}">
<text v-if="cata.section.status==1" style="font-size: 14px;">未开始</text>
<text v-if="cata.section.status==2" style="font-size: 14px;">进行中</text>
<text v-if="cata.section.status==9" style="font-size: 14px;">已完成</text>
</view>
</view>
<view >
<view v-for="(con,conIdx) in cata.children" :key="conIdx" class="catalog-con" @click="playContent(con,conIdx,catIdx)">
<view class="catalog-con-name" :class="{'color-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 v-else class="catalog">
<view >
<view v-for="(con,conIdx) in contentList" :key="conIdx" class="catalog-con" @click="playContent(con,conIdx,catIdx)">
<view class="catalog-con-name" :class="{'color-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>
</view>
<!--推荐课程-->
<view v-if="tabIndex==1 && !catalogShow" style="padding: 30upx;background-color: #fff;">
<view style="color: #333333; font-size: 32upx;font-weight: 600;padding-bottom: 20upx;">课程推荐</view>
<course-list :items="recommendCourses"></course-list>
</view>
<!--弹出窗口-->
<!--课程简介-->
<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>
<!-- 评分赞和踩 -->
<u-popup :show="scoreInfo.dlgShow" mode="center" @close="closeScore" @open="openScore">
<view style="text-align: center;padding: 50upx 100upx;">
<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>
<interact-share ref="comShare" :data="courseInfo"></interact-share>
</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 apiUserFollow from '@/api/phase2/userfollow.js'
import apiResOwner from '@/api/modules/resowner.js'
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import apiFavorites from '@/api/modules/favorites.js'
import {getContentType} from "@/utils/tools.js";
import studyUtil from '@/utils/study.js';
import {toScore,cutOrgNamePath,formatUserNumber} from '@/utils/tools.js';
import {mapGetters} from 'vuex'
export default {
data(){
return{
loading:false,//加载中
courseId:'',//当前课程的id
studyId: '',//当前学习的id
initContentId:'',//初始化的内容id
courseInfo:{id:'',name:''},//课程信息
teachers:[],//课程老师列表
recommendCourses:[],//推荐课程列表
catalogShow:false,//是否显示目录
totalContent:0,//课程内容数量
hasSection:false,//是否有目录
tabIndex:1,//显示的tab内容
scoreInfo:{dlgShow:false, score:5, has:false},//评分控制项
isPraise:false,//是否已点赞
isTrample:false,//是否已踩
isFavorite:false,//是否已收藏
isFollow:false,//是否已关注
toScore:toScore,
formatUserNumber:formatUserNumber,
getConType:getContentType,
isPlaying:false,
onplay:false,
touchNum : 0,
playerBoxShow:false,
summarylogShow: false,
scrollItemWidth:this.$width,
treePopupWidth:'400px',
fileBaseUrl:this.$config.fileUrl,
curSection:{},//当前所在的章
curContent:{
studyItemId:'',
status:1
},//当前的内容
conLink:{openType:1,url:''},//外连接内容
curriculumData:{url:'',isDrag:true,completeSetup:1,setupTage:0,second:0},// 课件内容
authorInfo:{aid:'',name:'',code:'',orgInfo:''},
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, // 当前倍速:
interactRuning:false,
scrollInfo:{
scrollLeft: 0,
scrollWidth: 0
},
handleTimeout:null,
isAppendTime:true,
appendStartTime: null, //记录追加的开始时间
appendHandle:null,
appentId:'',//当前追加的学习时长的id
appentInterval:30000,//追加学习时间的间隔 30秒加一次
preTime:-1
}
},
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;
},
},
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.courseInfo.id=options.id;
this.loadDetail();//加载课程数据
this.loadReCourses();//加载推荐课程
this.loadIsData();//加载关注,收藏,评价等信息
},
onShow(){
uni.setNavigationBarTitle({ title:'\u200E' })
//实时渲染当前的播放状态
},
onReady() {
this.videoPlayer=uni.createVideoContext("myVideo", this);
},
methods:{
loadDetail(){
let $this=this;
uni.showLoading({title:'加载中...'})
apiCourseStudy.studyIndex(this.courseId).then(rs=>{
if(rs.status != 200) {
uni.hideLoading();
$this.$refs.messager.show({message:rs.message,type:'error'});
return;
}
if(rs.result.contents.length==0){
$this.$refs.messager.show({message:'课程内容已删除或课程已不再使用',type:'error'});
return;
}
if(!rs.result.course.enabled){
$this.$refs.messager.show({message:'十分抱歉,此课程已停用,如需使用,请联系管理员。',type:'error'});
return;
}
$this.courseInfo=rs.result.course;
$this.scoreInfo.score=rs.result.course.score;
//处理老师数据
if(rs.result.teachers && rs.result.teachers.length > 0) {
let userIds = [];
//let ctoUsers = [];
rs.result.teachers.forEach(item => {
item.followed=false;
item.name= '';
item.orgInfo= '';
item.avatar= '';
item.code= '';
item.sex=null;
userIds.push(item.teacherId);
//检查是否已关注
apiUserFollow.has(item.teacherId).then(followRs=>{
if(followRs.status==200 && followRs.result){
item.followed=true;
}
})
});
$this.loadAuthorInfo(rs.result.teachers, userIds);
$this.teachers=rs.result.teachers;
}
let showConId=this.initContentId;
if(rs.result.course.type >10){
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;
}
});
})
}else if(rs.result.course.type==10){
let indexNum=0;
let delIndexs=[];
rs.result.contents.forEach((c,cidx) => {
c.status = 0; //
c.studyItemId = '';
c.lastStudyTime = 0;
if(c.sortIndex==1){
c.contentName=rs.result.course.name;
indexNum++;
if(indexNum>1){
delIndexs.push(cidx);
}
}else if(c.sortIndex==2){
c.contentName='作业';
}else if(c.sortIndex==3){
c.contentName='考试';
}else if(c.sortIndex==4){
c.contentName='评估';
}
});
if(delIndexs.length>0){
delIndexs.forEach(delIdx=>{
rs.result.contents.splice(delIdx,1);
})
}
}
this.contentList=rs.result.contents;//内容列表
this.totalContent=rs.result.contents.length;//一共有向个可以播放的内容
this.sectionList=rs.result.sections;
//处理学习内容
this.studyId = rs.result.studyId;
this.contentList.forEach(con=>{
rs.result.contentStudys.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
}
})
});
//设置正在学习的章节
if(this.curContent.studyItemId){
this.playContent(this.curContent,0);
//this.curSection=this.sectionList[0];
}else{
this.curContent=this.contentList[0];
this.playContent(this.curContent,0);
}
uni.hideLoading();
});
},
playContent(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.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);
}
},
loadReCourses(){
let dto={
sysType1:this.courseInfo.sysType1,
sysType2:this.courseInfo.sysType2,
sysType3:this.courseInfo.sysType3
}
apiCourseStudy.courseRecommends(dto).then(rs=>{
if(rs.status==200){
this.recommendCourses=rs.result;
}
})
},
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.name= author.name;
item.orgInfo=cutOrgNamePath(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);
}
});
},
loadUserInfo(uid){
apiUser.getByIds([uid]).then(res=>{
if(res.status==200){
this.authorInfo=res.result[0];
}
})
},
loadIsData(){
//加载是否关注,是否收藏,是否评价等
apiFavorites.has(1,this.courseId).then(rs=>{
if(rs.status==200 && rs.result){
this.isFavorite=true;
}else{
this.isFavorite=false;
}
})
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;
}
});
},
followUser(tea){
//实现关注处理
if(tea.followed){
apiUserFollow.remove(tea.teacherId).then(rs=>{
if(rs.status==200){
tea.followed=false;
this.$refs.messager.show({message:'取消关注',type:'success'});
}else{
this.$refs.messager.show({message:rs.message,type:'error'});
}
})
}else{
apiUserFollow.save(tea.teacherId).then(rs=>{
if(rs.status==200){
tea.followed=true;
this.$refs.messager.show({message:'关注成功',type:'success'});
}else{
this.$refs.messager.show({message:rs.message,type:'error'});
}
})
}
},
changeTab(idx){
this.tabIndex=idx;
},
showAllCatalog(){
this.catalogShow=true;
//定位目录
},
closeAllCatalog(){
this.catalogShow=false;
//定位目录
},
openScore(){
//显示评分弹窗
if(this.scoreInfo.has){
this.$refs.messager.show({message:'您已评过分',type:'error'});
return;
}
this.scoreInfo.dlgShow=true;
},
closeScore(){
this.scoreInfo.dlgShow=false;
},
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'});
}
});
}
},
openComment(){
//打开评论窗口,调用组件内事件
this.$refs.fiexdbar.openInput();
},
refreshComments(){
this.$refs.comments.loadData(false);
},
openShare(){
//console.log(this.$refs.fiexdbar,'this.$refs.fiexdbar');
//因为开始是v-if控制的所以这里获取不到必须显示时才会获取到所以需要单独的弄一个分享组件
this.$refs.comShare.openShare();
},
shareSuccess(rs){
this.$refs.messager.show({message:'分享成功',type:'success'});
},
addFavorite(){
if(this.loading){
return;
}
this.loading=true;
uni.showLoading({title:'处理中...'})
//需要判断是否已点赞,已点赞的不再加
let postData={
objType:1,
objId:this.courseId,
title:this.courseInfo.name,
}
if(this.isFavorite) {// 已经收藏,再次点击取消收藏
apiFavorites.remove(1,this.courseId).then(res=>{
this.loading=false;
if(res.status==200){
this.isFavorite=false;
this.$refs.messager.show({message:'已取消收藏',type:'success'});
}else{
console.log('取消收藏失败:'+res.message);
}
uni.hideLoading();
})
} else {
apiFavorites.save(postData).then(res=>{
this.loading=false;
if(res.status==200 && res.result){
this.isFavorite=true;
this.$refs.messager.show({message:'已加入收藏',type:'success'});
//发送消息
//this.messageSave(this.data.id,this.data.name,this.userInfo.name,this.data.sysCreateBy,this.data.sysCreateAid,'收藏了我发布的');
}else{
this.$refs.messager.show({message:'收藏失败',type:'error'});
console.log('加入收藏失败:'+res.message);
}
uni.hideLoading();
})
}
},
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'});
}
})
}
},
scrollHandler(e) {
//console.log(e);
this.scrollInfo = e.detail;
},
//以下是插入相关的处理
doubleClickVideo(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)
},
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);
}
})
},
statusClass(status){
let statusObj={
1:'nostart',
2:'studying',
9:'finish',
}
return statusObj[status]
}
}
}
</script>
<style lang="scss" scoped>
body{
background-color: #fff;
}
.playbox{
padding: 10upx;
//background-color: #000000;
}
.contentbox{
padding: 34upx;
background-color: #fff;
}
.tabrow{
display: flex;
border-bottom:1px solid #999999;
font-size: 28upx;
.tabrow-active{
font-size: 32upx;
color: #387DF7;
border-bottom: 4upx solid #007DFF;
}
.tabrow-item{
margin-right: 30upx;
line-height: 60upx;
text{
padding-bottom: 10upx;
}
}
}
.cinfo{
.cinfo-title{
color:#333333;
font-size: 32upx;
padding: 28upx 0upx;
}
.cinfo-tag1{
font-size: 22upx;
color: #6E7B84;
background: rgba($color: #387DF7, $alpha: 0.1);
border-radius: 16upx;
margin-left: 12upx;
margin-right: 12upx;
padding: 2upx 12upx;
}
.cinfo-tag2{
font-size: 22upx;
color: #D98135;
background: rgba($color: #FF7900, $alpha: 0.1);
border-radius: 16upx;
margin-right: 12upx;
padding: 4upx 12upx;
}
.desrow{
display: flex;
justify-content: space-between;
padding: 26upx 0upx;
.desrow-name{
color: #333333;
font-size: 28upx;
}
.desrow-value{
color: #666666;
font-size: 28upx;
}
.score{
color:#FB7303;
margin-left: 10upx;
font-weight: 700; font-size: 32upx;
}
}
.cinfo-btns{
display: flex;
justify-content: center;
.cinfo-btn{
margin:30upx 60upx;
}
}
}
.citembox1{
display: flex;
.citembox1-item{
width: 50%;
}
}
.citem{
margin: 10upx;
.citem-title{
color: #333333;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
overflow: hidden;
}
.citem-body{
background-color: #F7F8F9;
color: #333333;
height: 100upx;
padding: 20upx 30upx;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
.scroll-item{
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 30upx;
min-height: 100upx;
// 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;
}
}
}
}
}
.box-studying{
//color:#FFB30F;
color: #387DF7;
border: 1px dotted #387DF7;
}
.box-finish{
color: #3C7EFF;
}
.box-nostart{
color:#EE474A;
}
.color-studying{
// background: #FDF1D7;
//color: #FFB30F;
color: #387DF7;
}
.color-finish{
// background: #f3f9ff;
color: #666666;
}
.color-nostart{
// background: #ffe8e7;
color: #666666;
}
.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>