Files
learning-system-mobile/pages/study/courseStudy.vue
zhangsir a03ec48c8d 打包
2024-08-15 19:40:07 +08:00

2287 lines
74 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"></page-title> -->
<view class="playbox" v-if="isShowPdt"><!--内容播放区域-->
<view style="min-height: 440upx;" >
<view v-if="curContent.contentType==10" style="background-color: #000000;">
<!--视频-->
<view style="position: relative;">
<video-player
:url="blobUrl"
:blobId="blobId"
controls
:enable-play-gesture="true"
:inittime="curContent.lastStudyTime"
@play="onPlayerPlay"
@pause="onPlayerPause"
@ended="onPlayerEnded"
@timeupdate="onPlayerPlaying"
@fullscreenchange="onFullScreen"
:drag="curriculumData.isDrag"
style="width: 100%; object-fit: fill">
></video-player>
<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 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="blobUrl"
: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 class="about-gongsi-info" :style="{height:articleMore? '500upx':'auto'}" style="padding: 15px;text-indent:40px;line-height: 28px;position: relative;">
<u-parse :content="curContent.content"></u-parse>
</view>
<view v-if="articleMore" @click="showMore" style="text-align: center;color: #387DF7;"><text>查看更多</text> </view>
</view>
<div v-if="curContent.contentType == 50" style="min-height: 500px;">
<!--因为web-view 动态切换地址不好用所以这里先使用iframe-->
<iframe id="iframe-scorm" v-if="scormUrl" :src="scormUrl" @load="iframeScormLoad()" frameborder="0" scrolling="no" border="0px" style="width:100%;min-height:500px;border:0px;"></iframe>
</div>
<view v-if="curContent.contentType==52">
<!--外连接-->
<view v-if="conLink.openType == 1">
<view v-if="conLink.url!=''" style="min-height: 400px;position: relative;">
<web-view :src="conLink.url"></web-view>
</view>
</view>
<view v-else>
<div style="text-align: center;padding: 20px;">{{ curContent.contentName }}</div>
<div style="text-align: center;padding: 20px;">{{ conLink.url }}</div>
</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" v-if="courseInfo.name">
<view v-if="!catalogShow">
<view class="tabrow">
<view class="tabrow-item" @click="goTop">目录({{totalContent}})</view>
<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 class="player-box-tabrow">
<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 }} -->
<text style="cursor: pointer;"></text>
</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 }} -->
<text style="cursor: pointer;"></text>
</view>
</view>
</view>
</view>
<!--简介内容-->
<view v-if="tabIndex==1" class="cinfo">
<view class="cinfo-title" style="display: flex;flex-wrap: wrap;">
<view >
{{courseInfo.name}}
</view>
<view>
<text class="cinfo-tag1">{{convertTypeName(courseInfo.sysType1)}}</text>
<text v-if="courseInfo.sysType2!= '' && courseInfo.sysType2!= '0'" class="cinfo-tag2">{{convertTypeName(courseInfo.sysType2)}}</text>
<text v-if="courseInfo.sysType3!= '' && courseInfo.sysType3!= '0'" class="cinfo-tag2">{{convertTypeName(courseInfo.sysType3)}}</text>
</view>
</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;font-size: 24upx;">{{formatUserNumber(courseInfo.studys)}}人学习</view>
</view>
<view class="desrow" style="justify-content: flex-start;">
<view style="line-height: 60upx;"><text class="desrow-name">讲师</text></view>
<view style="flex: 1;">
<view v-for="(tea,teaIdx) in teachers" :key="tea.id" style="display: flex;justify-content: space-between;line-height: 60upx;">
<view>
<text class="desrow-value">{{tea.teacherName}}</text>
<text class="desrow-value" style="font-size: 24upx;margin-left: 6upx;color: #999999;">({{tea.orgInfo}})</text>
</view>
<view @click="followUser(tea)" style="color: #387DF7;">
<text class="concern" v-if="tea.followed">已关注</text>
<text v-else class="concern">+关注</text>
</view>
</view>
</view>
</view>
<view class="desrow">
<view style="display: flex;">
<text class="desrow-name">课程评分</text>
<u-rate readonly v-if="courseInfo.score>0" :count="5" activeColor="#F37101" :size="16" v-model="courseInfo.score"></u-rate>
<text class="score">{{toScore(courseInfo.score)}}</text>
</view>
</view>
<view class="desrow" v-if="myScore>0">
<view style="display: flex;">
<text class="desrow-name">我的评分</text>
<u-rate readonly :count="5" activeColor="#F37101" :size="16" v-model="myScore"></u-rate>
<text class="score">{{toScore(myScore)}}</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="{'color-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" :class="{'box-studying':curContent.id==con.id}">
<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><text v-if="isFavorite">已收藏</text><text v-else>收藏</text> </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" :favorites="false" :shares="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"> <image src="/static/images/close.png" style="width: 50upx;height: 50upx;"></image> </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)">
<view class="catalog-con-name" :class="{'color-studying':curContent.id==con.id}">
<text>{{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" :closeable="false" :closeOnClickOverlay="false" :round="14" @close="closeScore" @open="openScore">
<view class="dlgscore">
<view class="dlgscore-top">
<view class="dlgscore-title">课程评价</view>
<view class="dlgscore-desc">对课程进行评分吧</view>
<view class="dlgscore-score">
<u-rate :count="5" :size="35" activeColor="#F37101" v-model="scoreInfo.score"></u-rate>
</view>
</view>
<view class="dlgscore-btns">
<view class="dlgscore-cancel">
<text @click="closeScore">取消</text>
</view>
<view class="dlgscore-submit">
<text @click="addScore()">提交</text>
</view>
<!-- <u-button type="primary" @click="addScore()" text="提交评分"></u-button> -->
</view>
</view>
</u-popup>
<interact-share ref="comShare" :data="courseInfo":type="1"></interact-share>
</view>
</template>
<script>
import config from '@/config/index.js'
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 apiStat from '@/api/phase2/stat.js'
import apiResOwner from '@/api/modules/resowner.js'
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import apiMessage from '@/api/system/message.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,mapActions} from 'vuex'
export default {
data(){
return{
tentative: false,
isShowPdt: true,
progressData: 0,
contentTypeV: '',
trueFalse: true,
loading:false,//加载中
courseId:'',//当前课程的id
studyId: '',//当前学习的id
initContentId:'',//初始化的内容id
courseInfo:{id:'',name:'',score:0},//课程信息
teachers:[],//课程老师列表
recommendCourses:[],//推荐课程列表
catalogShow:false,//是否显示目录
totalContent:0,//课程内容数量
hasSection:false,//是否有目录
tabIndex:1,//显示的tab内容
scoreInfo:{dlgShow:false, score:0, has:false},//评分控制项
isPraise:false,//是否已点赞
isTrample:false,//是否已踩
isFavorite:false,//是否已收藏
isFollow:false,//是否已关注
myScore:0,//我的评分如果是0表未评分
toScore:toScore,
formatUserNumber:formatUserNumber,
getConType:getContentType,
onplay:false,
touchNum : 0,
playerBoxShow:false,
summarylogShow: false,
scrollItemWidth:this.$width,
treePopupWidth:'400px',
fileBaseUrl:this.$config.fileUrl,
curSection:{},//当前所在的章
curContent:{id:'',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,
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,//追加学习时长的timeout句柄
appentId:'',//当前追加的学习时长的id
appentInterval:15,//追加学习时间的间隔 3秒加一次
preTime:-1,
blobUrl:'',//音视频的播放地址
blobId: '',
localTimeKey:'boeu-study-time' ,//本地存储的学习时长的key json格式
localTimeValue:0,//计算的时间
appendStudyOtherHandle:null,
articleMore:true,
scormUrl:'',
maxDuration:0, //非音频最大时长
cumulativeDuration:0, //非音频累计时长
defaultMaxTime:1800 //非音频默认最大时间
}
},
computed: {
...mapGetters(['userInfo','sysTypeMap']),
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.getSysTypeTree();
this.loadSysTypes();
this.loadReCourses();//加载推荐课程
this.loadIsData();//加载关注,收藏,评价等信息
this.loadMyScore();
},
onShow(){
uni.setNavigationBarTitle({ title:'\u200E' })
//实时渲染当前的播放状态
},
onReady() {
},
onHide(){
//清除定时任务,隐藏的时候不清除,因为没有停止播放
// this.clearTimeHandle();
console.log('触发onHide');
},
destroyed() {
this.clearTimeHandle();
},
methods:{
...mapActions({
// getResOwnerTree:'resOwner/getResOwnerTree',
// loadResOwners:'resOwner/loadResOwners',
getSysTypeTree:'sysType/getSysTypeTree',
loadSysTypes:'sysType/loadSysTypes'
}),
// 没有写播放时间
onPlayerPlay() {
this.playerBoxShow = false;
this.isAppendTime=true;
this.appendStudyTime();//启动追加学习时长
},
convertTypeName(code){
if(!code){return '';}
return this.sysTypeMap.get(code);
},
clearTimeHandle(){
if(this.appendStudyOtherHandle!=null){
window.clearTimeout(this.appendStudyOtherHandle);
}
if(this.appendHandle!=null){
window.clearTimeout(this.appendHandle);
}
if(this.handleTimeout!=null){
window.clearTimeout(this.handleTimeout);
}
},
iframeScormLoad(){
setTimeout(function(){
var scormIframe=document.getElementById('iframe-scorm');
if (scormIframe) {
let iframeWin = scormIframe.contentWindow;
let iframeDoc = scormIframe.contentDocument || scormIframe.document;
let cHeight = Math.max(iframeDoc.body.clientHeight,iframeDoc.documentElement.clientHeight);
let sHeight = Math.max(iframeDoc.body. scrollHeight,iframeDoc.documentElement.scrollHeight);
let winHeight = iframeWin.document.documentElement.scrollHeight || iframeWin.document.body.scrollHeight;
let lheight = Math.max(cHeight, sHeight);
let finalHeight = Math.max(lheight, winHeight );
scormIframe.height =finalHeight;
console.log('scormIframe.height',scormIframe.height);
}
},1500);
},
loadMyScore(){
apiCourseGrade.score({courseId:this.courseId}).then(rs=>{
if(rs.status==200){
this.myScore=rs.result.scores;
this.scoreInfo.has=true;
}
})
},
loadDetail(){
let $this=this;
uni.showLoading({title:'加载中...'})
apiCourseStudy.studyIndex(this.courseId).then(rs=>{
if(rs.status != 200) {
uni.hideLoading();
uni.showToast({title:rs.message,type:'fail'});
//$this.$refs.messager.show({message:rs.message,type:'error'});
return;
}
if(rs.result.contents.length==0){
//$this.$refs.messager.show({message:'课程内容已删除或课程已不再使用',type:'error'});
uni.showToast({title:'课程内容已删除或课程已不再使用',type:'fail'});
return;
}
if(!rs.result.course.enabled){
uni.showToast({title:'十分抱歉,此课程已停用,如需使用,请联系管理员。',type:'fail'});
//$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;
//console.log(showConId,'showConId');
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);
})
}
//定位初始化数据
rs.result.contents.forEach((c,cidx) => {
if(showConId!='' && c.id==showConId){
$this.curContent=c;
}
})
}
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.id){
this.playContent(this.curContent,0);
//this.curSection=this.sectionList[0];
}else{
let treelist=this.catalogTree;
//console.log(treelist,'treelist')
if(treelist.length>0){
this.curSection=treelist[0].sec;
this.curContent=treelist[0].children[0];
}else{
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;
// }
// }
//this.curContent=this.contentList[0];
this.playContent(this.curContent,0);
}
uni.hideLoading();
});
},
playContent(con,conIndex,catIndex){
this.isShowPdt = true
// 视频设置禁用处理逻辑,如果用户已全部观看完该视频则设置为能全部拖动的逻辑把isDrag设置为true即可,同时删除本地存储的数据
if(con.progressVideo ===1){
var obj = JSON.parse(con.content)
obj.isDrag = true
con.content = JSON.stringify(obj)
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
//alert(con.progressVideo+'--'+con.id + '--'+JSON.stringify(arr))
delete arr[con.id];
localStorage.setItem('videoProgressData',JSON.stringify(arr))
}
if(con.progressVideo>0 && con.progressVideo !==1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
arr[con.id] = con.progressVideo
localStorage.setItem('videoProgressData',JSON.stringify(arr))
}
console.log('更换播放内容 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){
//uni.showToast({title:'请按顺序学习',type:'fail'});
this.$refs.messager.show({message:'请按顺序学习',type:'error'});
return;
}
}
}
}
//切换播放内容
this.changePlayRes(con);
},
loadReCourses(){
let dto={
sysType1:this.courseInfo.sysType1,
sysType2:this.courseInfo.sysType2,
sysType3:this.courseInfo.sysType3
}
apiCoursePortal.recommendList(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;
}
});
},
//更换播放内容
changePlayRes(con){
this.tentative = false;
this.trueFalse = true;
this.videoPlayingTime = 0
this.scormUrl='';//清空地址
this.articleMore=true;
this.clearTimeHandle();
//this.curContent=0;
// console.log(con,'con');
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==50){ //scorm课件的内容
apiCourseFile.detail(con.contentRefId).then(cfrs => {
if(cfrs.status==200){
//this.curCFile = cfrs.result;
//this.scormUrl=cfrs
let pars='?mode=normal&r='+Math.random();
pars+='&scormId='+cfrs.result.id;
pars+='&courseId='+this.courseId;
pars+='&contentId='+con.id;
pars+='&studentId='+this.userInfo.aid;
pars+='&studentName='+encodeURIComponent(this.userInfo.name);
pars+='&lmsId='+this.studyId;
pars+='&scoId=';//不指定scorm模块自动根据学习记录定位
pars+='&r='+Math.random();//加一个随机数,以便重新加载
let urlPre=window.location.protocol;
let configUrl=config.scormPlayer;
configUrl=urlPre+configUrl.substring(configUrl.indexOf(':')+1);
this.scormUrl=configUrl+pars;//播放的首页
console.log(this.scormUrl,'this.scormUrl')
}
});
}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;
}
if (this.conLink.openType == 2) {
//新的窗口直接打开
location.href=this.conLink.url
}
} else if(con.contentType==10 || con.contentType==20) {
if(con.content.startsWith('\{')){
var d = JSON.parse(con.content)
// if(d.url=="/course/2024/4/1224670812274712576.mp4") d.isDrag = false
this.curriculumData=d;
}else{
this.curriculumData.url=con.content;
}
console.log('this.curriculumData:::',this.curriculumData)
this.blobUrl=this.fileBaseUrl+this.curriculumData.url;
this.blobId = con.id;
}
//console.log(con.contentType,'con.contentType');
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;
//50事scorm项目单独计时
if(con.contentType>20 && con.contentType !== 50){
let $this=this;
//用户的学习时长,音视频课程学习,单独的处理,不再追加学习时长
this.isAppendTime = false;
this.appendStudyOtherHandle = setTimeout(function() {
// 开始之前把响应式清空
$this.maxDuration = 0;
$this.cumulativeDuration = 0;
// 没有设置默认时长三十分钟,
$this.maxDuration = con.duration !== 0 ? con.duration * 2 : $this.defaultMaxTime;
//静默处理
apiStat.sendEvent({
"key": "StudyCourse",//课程学习的key
"title": "学习课程",//事件的标题
"parameters":"second:15",//second:value,total:value 本次的学习时长
"content": "学习课程【"+$this.courseInfo.name+"】",//事件的内容
"objId": $this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"h5",
"objInfo": ""+$this.courseInfo.name,
"aid":$this.userInfo.aid, //当前登录人的id
"aname":$this.userInfo.name,//当前人的姓名
"status": 1 //状态
}).then(rs=>{
if(rs.status !== 200) {
console.log(rs.message);
}
});
$this.appendStudyOtherTime();
}, 1000 * 15); //非音视频课程学习,15秒后记录因为一次记录是60秒
//this.appendStudyTime();
//非视频音频的5秒后学习完成
if(con.contentType!=50){
this.handleTimeout = setTimeout(function(){$this.saveStudyInfo();},5000);//5秒后记录学习完成
}else{
//scorm课件不记录完成情况由播放回调记录完成情况
//当前先保存学习记录,未学习状态
this.saveScormStudy();
}
}
},
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'});
}
})
}
},
goTop(){
window.scrollTo(0, 0);
this.showAllCatalog()
this.isShowPdt = false
},
changeTab(idx){
this.tabIndex=idx;
},
showAllCatalog(){
this.catalogShow=true;
//定位目录
},
closeAllCatalog(){
this.catalogShow=false;
this.isShowPdt = true
//定位目录
},
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;
if(this.courseInfo.score==0){
this.courseInfo.score=postData.score;
}
if(this.myScore==0){
this.myScore=postData.score;
}
this.$refs.messager.show({message:'评分成功,谢谢您的评分',type:'success'});
//发送评分事件
let event = {
key: "ScoreCourse", //后台的事件key 发布文章且审核通过
title: "完成课程评分", //事件的标题
source:"h5",//移动端是2
parameters: "", //用户自定义参数 name:value,name:value
content: "给课程评分", //事件的内容
objId: this.courseInfo.id, //关联的id
objType: 1, //关联的类型
objInfo: this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name, //当前人的姓名
status: 1 //状态直接写1
}
apiStat.sendEvent(event);
}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 firstTeacher={};
if(this.teachers.length>0){
firstTeacher=this.teachers[0];
}
//需要判断是否已点赞,已点赞的不再加
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'});
//发送消息
let message={
content:this.userInfo.name+'收藏了我的课程-'+this.courseInfo.name,
refId:this.courseInfo.id,
refType:1,
source:1,
pageType:1,
pageParams:this.courseInfo.id,
sendAid:this.userInfo.aid,
sendName:this.userInfo.name,
acceptName:firstTeacher.teacherName,
acceptId:firstTeacher.teacherId,
title:'系统消息',
sendType:1,
conType:this.courseInfo.type,
}
apiMessage.save(message).then(res=>{
if(res.status!=200){ console.log('发送消息失败') }
})
}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;
let firstTeacher={};
if(this.teachers.length>0){
firstTeacher=this.teachers[0];
}
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--;
let event = {
key: "CancelPraise",//点赞
title: "取消点赞",//事件的标题
parameters:"author:"+firstTeacher.teacherId,//用户自定义参数 name:value,name:value
content: "取消点赞课程",//事件的内容
source:"h5",//移动端是2
objId: this.courseId,//关联的id
objType: "1",//关联的类型
objInfo: this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name,//当前人的姓名
status: 1 //状态直接写1
}
apiStat.sendEvent(event);
}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++;
let event = {
key: "Praise",//点赞
title: "点赞",//事件的标题
parameters:"author:"+firstTeacher.teacherId,//用户自定义参数 name:value,name:value
content: "点赞了课程",//事件的内容
source:"h5",//移动端是2
objId: this.courseInfo.id,//关联的id
objType: "1",//关联的类型
objInfo: this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name,//当前人的姓名
status: 1 //状态直接写1
}
apiStat.sendEvent(event);
let message={
content:this.userInfo.name+'点赞了我的课程-'+this.courseInfo.name,
refId:this.courseInfo.id,
refType:1,
source:1,
pageType:1,
pageParams:this.courseInfo.id,
sendAid:this.userInfo.aid,
sendName:this.userInfo.name,
acceptName:firstTeacher.teacherName,
acceptId:firstTeacher.teacherId,
title:'系统消息',
sendType:1,
conType:this.courseInfo.type,
}
apiMessage.save(message).then(res=>{
if(res.status!=200){ console.log('发送消息失败') }
})
}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;
},
//以下是播放相关的处理
saveStudyDuration(duration) { //保存本地存储的学习时长
if (duration > 0) {
//发送用户学习事件
//console.log('保存到后台学习时长='+duration);
let postData={
"key": "StudyCourse",//课程学习的key
"title": "学习课程",//事件的标题
"parameters":"second:"+duration,//second:value,total:value 本次的学习时长
"content": "学习课程【"+this.courseInfo.name+"】",//事件的内容
"objId": this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"h5",
"objInfo": ""+this.courseInfo.name,
"aid":this.userInfo.aid, //当前登录人的id
"aname":this.userInfo.name,//当前人的姓名
"status": 1 //状态
}
//静默处理
apiStat.sendEvent(postData).then(rs=>{
if(rs.status == 200) {
//this.appendStartTime = new Date();//重新计时
studyUtil.clearStudyDuration(); //清除本地存储
} else {
console.log(rs.message);
}
});
}
},
//结束追加学习时长
stopStudyTime(){
//console.log('停止追加学习时长');
this.isAppendTime=false;
//暂停让他为空 从新计时
this.appendStartTime = null
if (this.appendHandle != null) {
window.clearTimeout(this.appendHandle);
}
},
//追加学习时长, flag是否提交到后台
appendStudyTime() {
// 暂停的时候重新从十五秒开始
if(!this.appendStartTime){
this.appentInterval = 15
}
//重新覆盖时间
this.appendStartTime = new Date();
//console.log('开始追加学习时长',this.isAppendTime);
if (this.studyId == '') {
return;
}
if (!this.curContent.id) {
return;
}
//清除之前的
if(this.appendHandle != null) {
window.clearTimeout(this.appendHandle);
}
if (!this.isAppendTime) {
return;
}
//启动下次追加学习时长
this.appendHandle = setTimeout(() => {
let endTime = new Date().getTime();
this.appentInterval = 60;
let duration = Math.round((endTime - this.appendStartTime) / 1000);
this.appendStudyTime();
this.saveStudyDuration(duration);
}, this.appentInterval * 1000);
},
// appendStudyTime() {
// //console.log('开始追加学习时长',this.isAppendTime);
// if (this.studyId == '') {
// return;
// }
// if (!this.curContent.id) {
// return;
// }
// //清除之前的
// if(this.appendHandle != null) {
// window.clearTimeout(this.appendHandle);
// }
// if (!this.isAppendTime) {
// this.appendStartTime = null;
// return;
// }
// //首先从本地读取
// let duration = studyUtil.getStudyDuration();
// //console.log('追加学习时长,当前本地积累的学习时长='+duration);
// //追加学习长
// let $this = this;
// if (this.appendStartTime == null) {
// this.appendStartTime = new Date();
// this.appendHandle = setTimeout(function() {
// $this.appendStudyTime();
// }, $this.appentInterval); //设置定时追加学习时长
// //保存之前的
// if (duration >= 60 ) {
// this.saveStudyDuration(duration);
// }
// return;
// }
// //如果当前追加开始时间不为空
// let now = new Date();
// let m = now.getTime() - this.appendStartTime.getTime(); //相差的毫秒数
// let sen = Math.round(m / 1000); //计算秒数
// // 每次添加的是定时器计时的时间
// duration = duration + sen;//追加的是秒
// if (duration >= 60) { //一分钟保存一次
// this.saveStudyDuration(duration);
// } else {
// studyUtil.setStudyDuration(duration); //添加到本地存储中
// }
// //重新覆盖时间
// this.appendStartTime = new Date();
// //启动下次追加学习时长
// this.appendHandle = setTimeout(function() {
// $this.appendStudyTime();
// }, $this.appentInterval);
// },
appendStudyOtherTime() { //非音视频课学习时长的增加,每一分钟保存一次
//console.log('开始追加学习时长',this.isAppendTime);
if (this.studyId == '') {
return;
}
if (!this.curContent.id) {
return;
}
//每一分钟保存一次
// 取消阅读的每分钟六十秒的计时,最多是设置的时间或默认时间
let $this=this;
let startTime = new Date().getTime();
this.appendStudyOtherHandle = setTimeout(function() {
let endTime = new Date().getTime();
let totalTime = Math.round((endTime - startTime) / 1000);
$this.cumulativeDuration += totalTime;
if($this.cumulativeDuration <= $this.maxDuration){
//静默处理
$this.sendOtherTime(totalTime)
$this.appendStudyOtherTime();
}else{
clearTimeout(this.appendStudyOtherHandle);
$this.cumulativeDuration = 0;
$this.maxDuration = 0;
}
}, 1000*60);
},
sendOtherTime(totalTime){
apiStat.sendEvent({
"key": "StudyCourseOther",//课程学习的key
"title": "非音视频课内容",//事件的标题
"parameters":"second:" + totalTime,//second:value 本次的学习时长
"content": "学习课程",//事件的内容
"objId": this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"h5",
"objInfo": ""+this.courseInfo.name,
"aid":this.userInfo.aid, //当前登录人的id
"aname":this.userInfo.name,//当前人的姓名
"status": 1 //状态
}).then(rs=>{
if(rs.status != 200) {
console.log(rs.message);
}
});
},
//先保存学习的内容,针对于音视频的内容
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.tentative && 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');
},
onPlayerPause(){
this.stopStudyTime();
},
onPlayerEnded(){
this.playerBoxShow=true;
this.stopStudyTime();
if(this.curContent.status<9){
this.finishStudyItem();
}
},
onPlayerPlaying(e){
if(e.detail.currentTime > 2 && this.trueFalse && this.curContent.status < 9){
let params ={
studyId: this.studyId,//学习id,
courseId: this.courseId,//课程id,
contentId: this.curContent.id,//内容id,
contentType: this.curContent.contentType,
contentName: this.curContent.contentName,//内容名称
progress: 1,
status: 2,
contentTotal:this.totalContent
}
apiCourseStudy.studyContent(params)
this.trueFalse = false
}
//console.log("当前播放11",itme);
//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 || completeType == 0) {
completeSecond = 5; //如果没有就采用默认的时间了
}
if (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 (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
}
//alert(3+'--'+this.curriculumData.isDrag +'---'+this.curContent.progressVideo)
if(!this.curriculumData.isDrag && this.curContent.progressVideo !=1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
console.log('this.curContent.progressVideo::',arr[this.blobId],this.curContent.progressVideo,arr[this.blobId])
if(arr[this.blobId] && this.curContent.progressVideo<arr[this.blobId]) {
postData.progressVideo = arr[this.blobId]
postData.contentId = this.curContent.id
postData.courseId = this.curContent.courseId
}
}
//alert(intTime+'----'+this.videoPlayingTime)
apiCourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
audioPlay(){
this.isAppendTime=true;//开始记录音视频的学习时长
this.appendStudyTime();//开始追加学习时长
// 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(){
this.stopStudyTime();
if(this.curContent.status<9){
this.finishStudyItem();
}
},
audioPause(){
this.stopStudyTime();
},
audioPlaying(e,second){
this.isAppendTime=true;//打开追加载学习时长
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(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
}
if(!this.curriculumData.isDrag && this.curContent.progressVideo !=1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
if(arr[this.blobId] && this.curContent.progressVideo<arr[this.blobId]) {
postData.progressVideo = arr[this.blobId]
postData.contentId = this.curContent.id
postData.courseId = this.curContent.courseId
}
}
//alert(this.preTime!=intTime +'---'+ saveTime +'---'+ this.curContent.studyItemId)
apiCourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
saveScormStudy() {
//只记录SCORM课件的学习
if(this.curContent.contentType!=50){
return;
}
if(this.curContent.status==9){
//已学习完的,不用再添加
return;
}
let params ={
studyId: this.studyId,//学习id,
courseId: this.courseId,//课程id,
contentId: this.curContent.id,//内容id,
contentType: this.curContent.contentType,
contentName: this.curContent.contentName,//内容名称
progress: 1,
status: 2,
contentTotal:this.totalContent
}
apiCourseStudy.studyContent(params).then(res=>{
if(res.status == 200) {
this.curContent.status=2;//完成
this.curContent.studyItemId=res.result;//学习记录id
}else{
console.log('记录学习失败:'+res.message+''+res.error);
}
})
},
//还需要记录播放时间
saveStudyInfo() { //记录课件学习信息
this.tentative = true;
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,
contentType: this.curContent.contentType,
contentName: this.curContent.contentName,//内容名称
progress: 100,
status: 9,
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]
},
showMore(){
this.articleMore=false;
}
}
}
</script>
<style lang="scss" scoped>
.concern{
font-size: 24upx;
border: 1upx solid #387DF7;
padding: 3upx 20upx;
border-radius: 30upx;
}
.pinglun{
/deep/ .comments{
padding: 0;
.comments-top{
display: none;
}
}
/deep/ .interact-fixed {
.interact-bar{
padding-right: 40upx;
}
}
/deep/ .interact-bar{
padding-left: 0 !important;
}
/deep/ .field-right{
width: 0 !important;
}
/deep/ .interact-bar-item{
width: 100% !important;
.field{
width: 100% !important;
}
}
// /deep/ .interact-bar{
// // padding-left: 0;
// }
// /deep/ .field{
// width: 448upx;
// }
// /deep/ .field-right{
// margin-right: 60upx;
// }
}
body{
background-color: #fff;
}
.playbox{
//padding: 10upx;
background-color: #fff;
}
.contentbox{
padding: 34upx;
background-color: #fff;
}
.player-box{
position: absolute;
// top: 62px;
// left: 184px;
width: 200px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
height: 147px;
background:#a9abb3;
opacity: 0.8;
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;
}
}
.tabrow{
display: flex;
border-bottom:1px solid rgba(153,153,153,0.14);
font-size: 28upx;
position: relative;
.tabrow-active{
font-size: 32upx;
color: #387DF7;
border-bottom: 4upx solid #007DFF;
}
.tabrow-item{
margin-right: 30upx;
line-height: 60upx;
font-weight: 600;
text{
padding-bottom: 10upx;
}
}
.player-box-tabrow{
position: absolute;
top: -20px;
right:-20px;
// left: 184px;
// width: 200px;
// left: 50%;
// top: 50%;
// transform: translate(-50%, -50%);
// height: 147px;
// background:#a9abb3;
// opacity: 0.8;
// border-radius: 33px;
// text-align: center;
padding: 20px;
box-sizing: border-box;
image{
width: 20px;
height: 20px;
vertical-align: middle;
margin-right: 4px;
// 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;
}
}
}
.cinfo{
.cinfo-title{
min-height: 18upx;
color:#333333;
font-size: 32upx;
padding: 28upx 0upx;
}
.cinfo-tag1{
font-size: 22upx;
color: #528CEC;
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;
margin-top: 66upx;
.cinfo-btn{
flex: 1;
font-size: 28upx;
text-align: center;
color:#999999;
}
}
}
.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;
border-radius: 4upx;
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;
margin-right: 20upx;
.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: 1upx solid rgba(56,125,247,0.14);
}
.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;
white-space: nowrap;
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;
}
.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);
}
.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:last-child{
border: none;
}
.catalog-con{
display: flex;
justify-content: space-between;
padding:30upx 0upx 30upx 30upx;
padding-right: 0;
border-bottom: 1px solid rgba(153,153,153,0.08);
.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;
}
}
}
.dlgscore{ //评分的样式
.dlgscore-top{
text-align: center;
padding: 50upx 100upx 0upx 100upx;
.dlgscore-title{
text-align: center;
font-size: 36upx;
}
.dlgscore-desc{
text-align: center;
color: #999999;
font-size: 24upx;
padding-top: 10upx;
}
.dlgscore-score{
padding-top: 40upx;
display: flex;
justify-content: center;
}
}
.dlgscore-btns{
margin-top: 60upx;
height: 100upx;
display: flex;
justify-content: center;
border-top: 1px solid rgba(153,153,153,0.14);
.dlgscore-cancel{
text-align: center;
width: 49%;
border-right:1px solid rgba(153,153,153,0.14);
line-height: 100upx;
color: #666666;
}
.dlgscore-submit{
text-align: center;
width: 50%;
line-height: 100upx;
color: #387DF7;
}
}
}
.about-gongsi-info{overflow: hidden; position: relative;}
.about-gongsi-info::after{
content: '';
position: absolute;
width: 100%;
height: 30px;
background: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 1)));
background: -moz-linear-gradient(top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
background: -o-linear-gradient(top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
background: linear-gradient(top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#0ff, endColorstr=#fff, GradientType=0);
bottom: 0;
left: 0;
}
</style>