Files
learning-system-portal/src/views/study/PortalIndex.vue
2024-05-13 17:29:35 +08:00

1494 lines
51 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>
<div>
<!-- 课程详情点击应该传参的 -->
<portal-header current="course" :goSearch="1"></portal-header>
<div class="portal-content xcontent">
<el-breadcrumb separator-class="el-icon-arrow-right" class="breadname">
<el-breadcrumb-item :to="{ path: '/course' }">课程列表</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: `/course/detail?id=${courseId}` }">课程详情</el-breadcrumb-item>
<el-breadcrumb-item>课程学习</el-breadcrumb-item>
</el-breadcrumb>
<!-- <span style="display:block;margin-bottom:10px">课程列表 > 课程详情 > 课程学习</span> -->
<div style="background-color: #FFFFFF; border-bottom:1px solid #eee; display: flex;justify-content: space-between;">
<div class="portal-content-title">{{ courseInfo.name }}</div>
<div style="padding-top: 15px;padding-right: 30px;"><interactBar :type="1" :data="courseInfo" :comments="false" :praises="false" :views="false"></interactBar></div>
</div>
<el-row>
<el-col :span="16">
<div style="min-height: 450px;">
<!-- <div style="background-color: #FFFFFF;font-weight: 600;border-bottom:1px solid #d0d0d0 ;padding: 10px;font-size: 22px;color: #333333;">{{ courseInfo.name }}</div> -->
<!--课程资源内容播放-->
<div class="player" style="width: 100%;border: 1px solid #ffffff;background-color: #FFFFFF;overflow: auto;">
<div>
<div v-if="resType == null || resType == 0">
<!--先显示视频图片-->
<course-image v-if="courseInfo.id != ''" :course="courseInfo"></course-image>
</div>
<div v-if="resType == 10" style="position: relative;">
<videoPlayer id="myVideoPlayer" v-if="resType == 10"
:src="blobUrl"
@onPlayerPlaying="onPlayerPlaying"
:initTime="contentData.lastStudyTime"
@onPlayerPlay="onPlayerPlay"
:isDrag="curriculumData.isDrag"
@onFullscreen="onFullscreen"
@onPlayerPause="onPlayerPause"
@onPlayerEnded="onPlayerEnded"
></videoPlayer>
<div class="player-box" v-if="playerBoxShow">
<div class="player-praise" style="cursor: pointer;">
<div @click="praiseContent">
<img class="icon-small" v-if="isPraise" :src="require('@/assets/images/icon/praise-active.png')" />
<img class="icon-small" v-else :src="require('@/assets/images/icon/zhan.png')" />
<!-- {{ courseInfo.praises }} -->
<div style="color:#fff;cursor: pointer;"></div>
</div>
<div style="margin-left: 15px;cursor: pointer;" @click="treadContent">
<img class="icon-small" v-if="isTrample" :src="require('@/assets/images/icon/trample-active.png')" />
<img class="icon-small" v-else :src="require('@/assets/images/icon/cai.png')" />
<!-- {{ courseInfo.trampleCount }} -->
<div style="color:#fff;cursor: pointer;"></div>
</div>
</div>
<div v-if="!scoreInfo.has" class="player-rate">
<el-rate v-model="scoreInfo.score" text-color="#ff9900" score-template="{value}" void-color="#fff" @change="addScore"></el-rate>
</div>
<div v-if="scoreInfo.has" style="padding-top: 5px;display: flex;">
<div class="player-rate" style="padding-left: 35px;">
<el-rate disabled v-model="courseInfo.score" :allow-half="true" ></el-rate>
</div>
<span class="score-text" style="margin-top:35px">
<span style="color:#ffb30f;">{{ toScore(courseInfo.score) }}</span>
<span style="font-size: 12px;color: #fff"></span>
</span>
</div>
</div>
</div>
<div v-if="resType == 20">
<div class="con-audio">
<div class="con-audio-title">{{ contentData.contentName }}</div>
<div class="con-audio-player">
<audioPlayer
v-if="resType == 20"
:url="fileBaseUrl + curriculumData.url"
:name="contentData.contentName"
@onPlaying="audioPlaying"
:isDrag="curriculumData.isDrag"
@onPlay="audioPlay"
@onPause="audioPause"
@onPlayEnd="audioEnd"
></audioPlayer>
</div>
</div>
</div>
<div v-if="resType == 40">
<div style="padding: 10px;color: #ed0000; " v-if="curCFile.converStatus < 2 && !contentData.content">
<div>此课程内容无法预览请联系管理员</div>
</div>
<div style="padding: 10px;color: #ed0000;" v-if="curCFile.converStatus == 3 && !contentData.content">
此课程内容无法预览请联系管理员
</div>
<pdfPreview :autoScroll="true" v-if="resType == 40" :filePath="fileBaseUrl + contentData.content"></pdfPreview>
</div>
<div v-if="resType == 41"><div style="padding: 20px;" v-html="contentData.content"></div></div>
<div v-if="resType == 52">
<div v-if="contentData.content != ''">
<div class="hyper-link" v-if="conLink.openType == 2">
<div class="hyper-link-row">{{ contentData.contentName }}</div>
<div class="hyper-link-row">{{ conLink.url }}</div>
</div>
<div v-if="conLink.openType == 1"><iframe :src="conLink.url" style="width: 100%;border:0px;min-height: 473px;" frameborder="0"></iframe></div>
</div>
</div>
<div v-if="resType == 60"><homework v-if="resType == 60 && studyId != ''" :studyId="studyId" :content="contentData"></homework></div>
<div v-if="resType == 61"><exam v-if="resType == 61 && studyId != '' " :studyId="studyId" :content="contentData"></exam></div>
<div v-if="resType == 62" style="padding:5px">
<assess v-if="resType == 62 && studyId != '' && contentData.id" :studyId="studyId" :content="contentData"></assess>
</div>
</div>
</div>
<div class="course-interact">
<div class="score" style="display: flex;">
<div v-if="!scoreInfo.has" style="margin-left:10px;cursor: pointer;">
<!-- <el-popover placement="top" width="300" trigger="hover"> -->
<!-- <div style="text-align:center;line-height:50px;padding:20px 0px">
<div style="padding-top:30px"><el-button @click="addScore">提交评分</el-button></div>
</div> -->
<el-rate v-model="scoreInfo.score" @change="addScore"></el-rate>
<!-- <el-tag class="ref-score" slot="reference">去评分</el-tag> -->
<!-- </el-popover> -->
</div>
<div v-if="scoreInfo.has" style="padding-top: 5px;display: flex;">
<div style="padding-top: 0px;">
<el-rate disabled v-model="courseInfo.score" :allow-half="true" ></el-rate>
</div>
<div>
<span class="score-text">{{ toScore(courseInfo.score) }}</span>
<span style="font-size: 14px;"></span>
</div>
</div>
</div>
<div style="display: flex;justify-content: flex-end;cursor: pointer;">
<div @click="praiseContent">
<el-tooltip class="item" effect="light" :content="isPraise?'取消点赞':'点赞'" placement="top-start" :visible-arrow="false" popper-class="text-tooltip">
<img class="icon-small" v-if="isPraise" :src="require('@/assets/images/icon/praise-active.png')" />
<img class="icon-small" v-else :src="require('@/assets/images/icon/praise.png')" />
</el-tooltip>
{{ courseInfo.praises }}
</div>
<div style="margin-left: 15px;" @click="treadContent">
<el-tooltip class="item" effect="light" :content="isTrample?'取消踩':'踩'" placement="top-start" :visible-arrow="false" popper-class="text-tooltip">
<img class="icon-small" v-if="isTrample" :src="require('@/assets/images/icon/trample-active.png')" />
<img class="icon-small" v-else :src="require('@/assets/images/icon/trample.png')" />
</el-tooltip>
{{ courseInfo.trampleCount }}
</div>
</div>
</div>
<div style="padding-left:5px;margin: 14px 0px;background-color: #FFFFFF;" class="info">
<comments v-if="courseInfo.id && courseInfo.id != ''" :obj-type="1" :obj-id="courseInfo.id" :toUsers="toUsers"></comments>
</div>
</div>
</el-col>
<el-col :span="8">
<div class="catalog-box" style="min-height: 450px;">
<!-- <p class="title">课程目录</p> -->
<!-- <el-tabs type="border-card" v-model="ctabName" @tab-click="ctabChange">
<el-tab-pane label="课程目录" name="catalog"> -->
<div style="min-height: 500px;">
<div class="catalog">
<el-collapse style="border-top:none" class="catalog-row" v-model="activeNames" @change="handleChange">
<el-collapse-item v-for="(item, index) in catalogTree" :key="index" :name="index">
<!-- <template class="collapse-title" slot="title" > -->
<div style="display:flex;margin-bottom:18px;">
<!-- 标题 -->
<div style="flex:1;line-height:21px" class="mltit">
<el-tooltip class="item" effect="light" :content="item.section.name" placement="top-start">
<span style="font-size:16px;font-weight: 700;color: #343434;margin-left: 15px;">
{{ item.section.name }}</span>
</el-tooltip>
</div>
<!-- 状态 -->
<div style="text-align: right;">
<span :class="statusToContent(item.section.status).class">{{ statusToContent(item.section.status).text }}</span>
</div>
</div>
<!-- </template> -->
<ul>
<li @click="showRes(ele,i,index)" v-for="(ele, i) in item.children" :key="i" class="catalog-cell" style="display: flex;justify-content: space-between;">
<!-- <span :class="statusToContent(ele.status).class">{{ statusToContent(ele.status).text }}</span> -->
<div class="catalog-text">
<span :class="['title-type', contentData.id == ele.id ? 'type-click' : '', 'type-kuang']">{{ getType(ele.contentType) }}</span>
<el-tooltip class="item" effect="light" :content=" ele.contentName" placement="top-start">
<span :style="{ color: contentData.id == ele.id ? '#ffaa00' : '' }">{{ ele.contentName }}</span>
</el-tooltip>
</div>
<div>
<!-- <span style="margin-right: 5px;color: #6c6c6c; " v-if="ele.duration>0">{{parseInt(ele.lastStudyTime/60)}}/{{parseInt(ele.duration/60)}}</span> -->
<!--状态 有问题,未切换为正在进行的状态-->
<span :class="statusToContent(ele.status).class">{{ statusToContent(ele.status).text }}</span>
</div>
</li>
</ul>
</el-collapse-item>
</el-collapse>
</div>
</div>
<!-- </el-tab-pane>
</el-tabs> -->
</div>
<div style="margin-top: 11px;margin-left:18px">
<el-card :body-style="{ padding: '0px' }" class="teachers">
<div class="top">授课讲师</div>
<div>
<div class="teacher" v-for="(item, idx) in teachers" :key="idx">
<div class="teacher-avator">
<!-- <div class="teacher-text" v-if="item.authorInfo.avatar == ''">{{userAvatarText(item.teacherName)}}</div> -->
<el-avatar v-if="item.authorInfo.avatar !== ''" :src="fileBaseUrl + item.authorInfo.avatar" shape="circle" :size="50"></el-avatar>
<div v-else class="teacher-text">
<div v-if="item.authorInfo.sex === 1 "><img src="../../../public/images/Avatarman.png" alt=""></div>
<div v-else><img src="../../../public/images/Avatarwoman.png" alt=""></div>
</div>
</div>
<div class="teacher-info">
<div class="teacher-name">{{ item.teacherName }}</div>
<div class="teacher-remark" v-html="item.remark"></div>
</div>
</div>
</div>
</el-card>
</div>
</el-col>
</el-row>
</div>
<portal-footer></portal-footer>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import portalHeader from '@/components/PortalHeader.vue';
import portalFooter from '@/components/PortalFooter.vue';
import comments from '@/components/Portal/comments.vue';
import courseImage from '@/components/Course/courseImage.vue';
import exam from '@/components/Course/exam';
import homework from '@/components/Course/homework';
import assess from '@/components/Course/assess';
import interactBar from '@/components/Portal/interactBar.vue';
import apiStudy from '@/api/modules/courseStudy.js';
import apiVideoStudy from "@/api/modules/videoStudy.js";
import apiCourseGrade from '@/api/modules/courseGrade.js';
import apiPraises from '@/api/modules/praises.js';
import apiTrample from '@/api/modules/trample.js';
import apiCoursePortal from '@/api/modules/coursePortal.js';
import apiCourse from '@/api/modules/course.js';
import apiUser from '@/api/system/user.js';
import apiCourseFile from '@/api/modules/courseFile.js';
import { resListMap, resOwnerListMap, courseType, getType, toScore,userAvatarText } from '@/utils/tools.js';
import pdfPreview from '@/components/PdfPreview/index.vue';
import audioPlayer from '@/components/AudioPlayer/index.vue';
import videoPlayer from '@/components/VideoPlayer/index.vue';
import hyperLink from '@/components/Course/hyperLink.vue';
import studyUtil from '@/utils/study.js';
import {encrypt} from '@/utils/jsencrypt.js';
import cookies from 'vue-cookies'
export default {
name: 'ucStudyIndex',
components: { courseImage, portalHeader, portalFooter, hyperLink, comments, homework, exam, interactBar, assess, pdfPreview, audioPlayer, videoPlayer },
data() {
return {
curCFile:{
converStatus:4,
},
interactRuning:false,
playerBoxShow:false,
userAvatarText,
publicPath: process.env.VUE_APP_PUBLIC_PATH,
showiframe: false,
toScore,
courseId: '',//当前课程的id
studyId: '', //当前学习的id
initContentId: '', //初始化当前学习的内容节
blobUrl:'',//播放的文件地址新添加采用blob方式
contentData: {
studyItemId:'',
status:1
}, //当前的显示的内容
conLink: { openType: 1, url: '' }, //对于超连接的内容
curriculumData:{url:'',isDrag:true,completeSetup:0,setupTage:0,second:0},// 课件内容
courseInfo: { id: '', name: '' }, //课程信息
totalContent: 0, //课程内容数量
pageCount: 0,
currentPage: 0,
fileBaseUrl: process.env.VUE_APP_FILE_BASE_URL,
contentList: [],
sectionList: [],
teachers: [],
toUsers: [], //对于@教师的处理
getType: getType,
ctabName: 'catalog',
resType: null,
activeNames: [0, 1, 2, 3, 4,5,6,7,8,9],
scoreInfo: {
dlgShow: false,
score: 5,
has: false
},
isPraise: false,
isTrample: false,
appendStartTime: null, //记录追加的开始时间
appendHandle:null,
isAppendTime:false,//是否追加学习时长
appentId:'',//当前追加的学习时长的id
appentInterval:30000,//追加学习时间的间隔 30秒加一次
handleTimeout:null,
completed:[],
};
},
mounted() {
this.$watermark.set(this.userInfo.name + this.userInfo.loginName);
this.courseId = this.$route.query.id;
this.loadData();
},
computed: {
...mapGetters(['userInfo']),
catalogTree() {
let treeList = [];
this.completed = [];
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++;
}
}
if(c.status == 9) {
$this.completed.push(c.id);
}
treeNode.children.push(c);
}
});
if (finishCount == treeNode.children.length) {
sec.status = 9;
}
treeList.push(treeNode);
});
return treeList;
}
},
methods: {
createPlayUrl(fid,u){
let nowDate=new Date();
let ctime=parseInt(nowDate.getTime()/1000);
let beforeUrl=parseInt(nowDate.getTime()/1000)+'/'+fid;
//console.log(beforeUrl,'beforeUrl');
let urlSign=encodeURIComponent(encrypt(beforeUrl));
//console.log(urlSign,'urlSign');
cookies.set('PLAYSIGN_TIME', ctime);//写客户端的cookie保存
//以下判断是为了区分本地环境和服务器环境
if(process.env.NODE_ENV == 'development'){
this.blobUrl=process.env.VUE_APP_FILE_BASE_URL+u;
}else{
this.blobUrl=process.env.VUE_APP_BASE_API+'/xboe/m/course/cware/resource?sign='+urlSign;
}
//console.log(this.blobUrl,'this.blobUrl');
},
widthOpen(url) {
window.open(url, '_blank');
},
formatTime(duration){
let min=0;
if(duration>0){
min=parseInt(duration/60);
}
return min;
},
saveStudyItem(){ //先保存学习的内容,针对于音视频的内容
if(this.contentData.studyItemId) {
return;//已经有记录的,不需要再保存了
}
let params = {
studyId: this.studyId, //学习id,
courseId: this.courseId, //课程id,
contentId: this.contentData.id, //内容id,
contentType:this.contentData.contentType, //内容id,
contentName: this.contentData.contentName, //内容名称
progress: 0,
lastStudyTime:0,
status:2,
studyDuration:0,
contentTotal: this.totalContent
};
apiVideoStudy.saveStudyItem(params).then(res=>{
if(res.status == 200){
this.contentData.studyItemId=res.result.id;
this.contentData.status = 2;//进行中状态
}else{
console.log("记录学习失败:" + res.message + "" + res.error);
}
});
},
finishStudyItem(){ //设置完成学习的内容,针对于音视频的内容
if(!this.contentData.studyItemId){
// 这种可能没有不过这里也是为了万中那个1
this.saveStudyInfo();
}else{
let params={
itemId:this.contentData.studyItemId,
studyId:this.studyId,
courseId:this.courseId,
cnum:this.totalContent
}
apiVideoStudy.finishStudyItem(params).then(res=>{
if(res.status == 200){
this.contentData.status = 9;
this.contentData.progress = 100;
}else{
console.log("记录完成学习失败:" + res.message + "" + res.error);
}
});
}
},
onFullscreen(full){
let divId='videowatermark';
var div = document.getElementById('myVideoPlayer')
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<8;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.loginName+'</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";
div.appendChild(div3);
}else{
var markDiv=div.querySelector("#"+divId);
if(markDiv){
div.removeChild(markDiv);
}
}
},
onPlayerPlay() {
//console.log("开始播放");
this.playerBoxShow = false;
let $this=this;
//console.log(this.contentData.status,'this.contentData.status');
// if(this.contentData.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() {
//console.log("暂停");
},
onPlayerEnded() {
this.playerBoxShow = true;
if(this.contentData.status<9){
this.finishStudyItem();
}
},
onPlayerPlaying(itme) {
this.isAppendTime=false;
this.appendStartTime=null;
//console.log("当前播放"+itme);
//console.log("当前播放11"+itme);
if (this.contentData.contentType && this.contentData.contentType == 10){
let intTime = parseInt(itme);
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond || completeType==0){
completeSecond=5;//如果没有就采用默认的时间了
}
if(this.contentData.status<9){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let videDuration=this.contentData.duration;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else{
if(intTime>=completeSecond){
this.finishStudyItem();
}
}
}
//下面是每隔10秒记录一下次
let saveTime = Math.floor(intTime % 10);
if (intTime > 10 && intTime!=this.contentData.lastStudyTime && saveTime == 0 && this.contentData.studyItemId != '') {
this.contentData.lastStudyTime=intTime;
let postData = {
itemId: this.contentData.studyItemId,
videoTime: intTime
};
//console.log('记录播放时间')
apiStudy.studyVideoTime(postData).then(rs => {
if (rs.status != 200) {
console.log('记录播放时间错误');
}
});
}
}
},
audioPlaying(item,currentTime) {
//console.log("当前播放"+item);
let intTime = parseInt(currentTime);
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond || completeType==0){
completeSecond=5;//如果没有就采用默认的时间了
}
if(this.contentData.status<9){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let videDuration=this.contentData.duration;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else{
if(intTime>=completeSecond){
this.finishStudyItem();
}
}
}
//下面是每隔10秒记录一下次
let saveTime = Math.floor(intTime % 10);
if (intTime > 10 && intTime!=this.contentData.lastStudyTime && saveTime == 0 && this.contentData.studyItemId) {
this.contentData.lastStudyTime=intTime;
let postData = {
itemId: this.contentData.studyItemId,
videoTime: intTime
};
//console.log('记录播放时间')
apiStudy.studyVideoTime(postData).then(rs => {
if (rs.status != 200) {
console.log('记录播放时间错误');
}
});
}
},
audioPlay() {
//console.log("开始播放");
let $this=this;
// if(this.contentData.status!=9){
// let completeType=this.curriculumData.completeSetup;
// if(completeType==0){
// //默认5秒后学习完成.
// $this.handleTimeout= setTimeout(function() {$this.saveStudyInfo();}, 5000); //5秒后记录学习完成
// }else{
// //先记录进行中的学习内容
// this.saveStudyItem();
// }
// }
},
audioPause() {
//console.log("暂停");
},
audioEnd() {
//console.log("播放结束");
if(this.contentData.status<9){
this.finishStudyItem();
}
},
loadData() {
apiCoursePortal.detail(this.courseId,false).then(rs => {
if (rs.status == 200) {
//设置必须的字段
rs.result.sections.forEach(sec => {
sec.status = 0; //加入状态表未开始
rs.result.contents.forEach(c => {
c.status = 0; //初始化状态 ,未开始
c.studyItemId = ''; //初始化字段学习条目id
c.lastStudyTime = 0; //初始化上次一学习的时间,作用于视频插放
});
});
this.sectionList = rs.result.sections;
this.courseInfo = rs.result.course;
this.teachers = rs.result.teachers;
if (rs.result.teachers && rs.result.teachers.length > 0) {
let userIds = [];
let ctoUsers = [];
rs.result.teachers.forEach(item => {
item.authorInfo = { aid: '', name: '', orgInfo: '', avatar: '', code: '',sex:null, };
userIds.push(item.teacherId);
ctoUsers.push({ aid: item.teacherId, name: item.teacherName });
});
this.toUsers = ctoUsers;
this.loadAuthorInfo(rs.result.teachers, userIds);
}
this.contentList = rs.result.contents;
this.totalContent = rs.result.contents.length;
//加载学习的数据
this.loadStudyData();
} else {
this.$message.error(rs.message);
}
});
},
loadStudyData() {
let $this = this;
apiStudy.studyInfo(this.courseId).then(res => {
if (res.status == 200) {
if (res.result.signup){
this.loadScorePraiseAndTrample();
this.studyId = res.result.studyId;
//对已学习的内容进行比对,重要的字段, 学习内容id在后缀的
let playIndex = -1;
this.contentList.forEach((con, conIdx) => {
res.result.contents.forEach((scon, sconIdx) => {
if (scon.contentId == con.id) {
//定位显示的内容
if ($this.initContentId != '' && $this.initContentId == scon.contentId) {
//定位当前学习的内容,是上一次学习的内容
playIndex = conIdx;
} else {
if (sconIdx == 0 && con.contentType < 52){
playIndex = conIdx;
}
}
//console.log(scon.contentId,con.id);
con.lastStudyTime = scon.lastStudyTime;
//以下判断是为了兼容之前的问题,学习状态
if(scon.status){
con.status = scon.status;
}else{
con.status = 9;
}
con.studyItemId = scon.id; //这个就是学习内容条目的id
//console.log(scon.id,"scon.id");
//console.log(con,"scon.id");
}
});
});
//如果没有,就定位第一项内容
if (playIndex === -1) {
// this.showRes(this.contentList[0]);
this.showRes(this.catalogTree[0].children[0])
} else {
this.showRes(this.contentList[playIndex]);
}
} else {
this.$message.error('您还未报名');
// if (this.courseInfo.type == 10) {
// location.href = this.webBaseUrl + '/course/micro?id=' + this.courseId;
// } else {
location.href = this.webBaseUrl + '/course/detail?id=' + this.courseId;
// }
}
} else {
this.$message.error(res.message);
}
});
},
saveStudyInfo() {
//记录课件学习信息
if (this.contentData.contentType >= 60) {
//只有在课件页面停留超过5秒才会记录
return;
}
if (this.contentData.status == 9) {
//已学习完的,不用再添加
return;
}
let params = {
studyId: this.studyId, //学习id,
courseId: this.courseId, //课程id,
contentId: this.contentData.id, //内容id,
contentType:this.contentData.contentType,
contentName: this.contentData.contentName, //内容名称
progress: 100,
status:9,
contentTotal: this.totalContent
};
apiStudy.studyContent(params).then(res => {
if (res.status == 200) {
this.contentData.status = 9; //完成
this.contentData.studyItemId = res.result; //学习记录id
} else {
console.log('记录学习失败:' + res.message + '' + res.error);
}
});
},
saveStudyDuration(){ //保存本地存储的学习时长
let duration=studyUtil.getStudyDuration();
if(duration>0){
let postData = {
id:this.appentId,
studyId: this.studyId,
courseId: this.courseInfo.id,
contentId: this.contentData.id,
studyInfo:
this.courseInfo.name +
"-" +
this.contentData.contentName,
duration: duration
};
apiStudy.appendStudyTime(postData).then(rs => {
if (rs.status == 200){
this.appentId=rs.result;
studyUtil.clearStudyDuration();//清除本地存储
} else {
console.log(rs.message);
}
});
}
},
appendStudyTime(flag) {
if(this.studyId==''){
return;
}
if(!this.contentData.id){
return;
}
if(!this.isAppendTime){
this.appendStartTime =null;
return;
}
if(this.appendHandle!=null){
window.clearTimeout(this.appendHandle);
}
//首先从本地读取
let duration=studyUtil.getStudyDuration();
//追加学习时间
let $this = this;
if (this.appendStartTime == null) {
this.appendStartTime = new Date();
this.appendHandle=setTimeout(function() {$this.appendStudyTime();}, $this.appentInterval);
if(duration>0 && flag){
this.saveStudyDuration();
}
return;
}
let now = new Date();
let m = now.getTime() - this.appendStartTime.getTime(); //相差的毫秒数
let sen = parseInt(m / 1000); //计算秒数
duration=duration+sen;
if(flag) {
if(duration>0){
let postData = {
id:this.appentId,
studyId: this.studyId,
courseId: this.courseInfo.id,
contentId: this.contentData.id,
studyInfo:
this.courseInfo.name +
"-" +
this.contentData.contentName,
duration: duration
};
apiStudy.appendStudyTime(postData).then(rs => {
if (rs.status == 200){
$this.appentId=rs.result;
$this.appendStartTime = new Date(); //重置开始时间
studyUtil.clearStudyDuration();//清除本地存储
//this.appendHandle=setTimeout(function() {$this.appendStudyTime();}, $this.appentInterval);
} else {
console.log(rs.message);
}
});
}
} else {
$this.appendStartTime = new Date(); //重置开始时间
studyUtil.setStudyDuration(duration);//添加到本地存储中
}
this.appendHandle=setTimeout(function() {$this.appendStudyTime();},$this.appentInterval);
},
ctabChange(e) {
//当前已经不再使用
//console.log(e);
},
showRes(r,i,index) { //i:子节下标index:章下标
if(i!=undefined && index!=undefined && r.status<9) {
if(this.courseInfo.orderStudy) {
//判断上个是否学完
if(i == 0) {
if(index > 0) { //第一章 第一节
let preCatalog=this.catalogTree[index-1];
let last=preCatalog.children[preCatalog.children.length-1];
if(last.status!=9){
this.$message.warning('请按顺序学习');
return;
}
}
}else{
let pre=this.catalogTree[index].children[i-1];
if(pre.status!=9){
this.$message.warning('请按顺序学习');
return;
}
}
//判断是否是第一个未学完的
let isAllow=false;
let has=this.catalogTree.some(treeNode=>{
let hasNo=treeNode.children.some(child=>{
if(child.status<9){
if(child.id==r.id){
isAllow=true;
}
return true;
}else{
return false;
}
});
return hasNo;
});
if(has){
if(!isAllow){
this.$message.warning('请按顺序学习');
return;
}
}
}
}
this.playerBoxShow=false;
//显示内容部分
let $this = this;
this.resType = r.contentType;
this.contentData = r;
this.saveStudyDuration();
if(r.contentType == 10 || r.contentType == 20) {
if (r.content.startsWith('\{')) {
this.curriculumData = JSON.parse(r.content);
} else {
this.curriculumData.url = r.content;
}
//let url=process.env.VUE_APP_BASE_API+'/xboe/m/course/file/show?cf='+this.curriculumData.url;
//let url=this.fileBaseUrl+this.curriculumData.url;
this.createPlayUrl(r.contentRefId,this.curriculumData.url);
} else if (r.contentType == 40) {
// if (r.content != '' && r.content.indexOf('.pdf') == -1) {
apiCourseFile.detail(r.contentRefId).then(cfrs => {
if (cfrs.status == 200) {
r.content = cfrs.result.previewFilePath;
this.curCFile = cfrs.result;
if(cfrs.result.previewFilePath == '' && cfrs.result.filePath.indexOf('pdf') > -1) {
r.content = cfrs.result.filePath;
this.curCFile.converStatus=2;
}
if(r.content && r.content.indexOf('.pdf')>-1){
this.curCFile.converStatus=2;
}
} else {
$this.$message.error('加载pdf课件文件失败');
}
});
// }
} else if (r.contentType == 52) {
this.isAppendTime=false;
if (r.content.startsWith('\{')) {
this.conLink = JSON.parse(r.content);
} else {
this.conLink.url = r.content;
this.conLink.openType = 1;
}
if (this.conLink.openType == 2) {
//直接设置完成状态
this.widthOpen(this.conLink.url);
}
//this.conLink=
} else if (r.contentType == 61) {
// 考试
} else if (r.contentType == 60) {
// 作业
} else if (r.contentType == 62) {
// 评估
//评估不需要查找因为内容就是content中
console.log('评估处理');
}
if(this.contentData.status<2){
this.contentData.status=2;//进行中
}
if(this.contentData.contentType>20){ //非视频类的
this.isAppendTime=true;
this.appendStudyTime();
this.handleTimeout= setTimeout(function() {$this.saveStudyInfo();}, 5000); //5秒后记录学习完成
}
},
handleChange(val) {
console.log(val);
},
loadScorePraiseAndTrample() {
//加载是否请过分
apiCourseGrade.has(this.courseId).then(rs => {
if (rs.status == 200 && rs.result) {
this.scoreInfo.has = true;
}
});
apiPraises.has(1, this.courseId).then(rs => {
if (rs.status == 200 && rs.result) {
this.isPraise = true;
}
});
apiTrample.has(this.courseId).then(rs => {
if (rs.status == 200 && rs.result) {
this.isTrample = true;
}
});
},
addScore() {
let that = this;
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.$message.success('打分成功谢谢您的打分');
that.scoreInfo.has = true;
that.courseInfo.score = rs.result;
} else {
this.$message.error('打分处理失败请稍后再试');
}
});
}
},
praiseContent() {
if (this.isTrample) {
this.$message.error('您已踩过了不能再赞了');
return;
}
if(this.interactRuning){
return;
}
this.interactRuning=true;
let postData = {
objType: 1,
objId: this.courseId,
title: this.courseInfo.name
};
if (this.isPraise) {
apiPraises.remove(1, this.courseInfo.id).then(res => {
this.interactRuning=false;
if (res.status == 200) {
this.$message.info('已取消点赞');
this.isPraise = false;
this.courseInfo.praises--;
} else {
this.$message.error('取消点赞失败,请稍后再试');
}
});
} else {
apiPraises.save(postData).then(rs => {
this.interactRuning=false;
if (rs.status == 200) {
this.$message.success('点赞成功');
this.isPraise = true;
this.courseInfo.praises++;
} else {
this.$message.error('点赞失败,请稍后再试');
}
});
}
},
treadContent() {
if (this.isPraise) {
this.$message.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.$message.info('已取消踩');
this.isTrample = false;
this.courseInfo.trampleCount--;
} else {
this.$message.error('取消失败,请稍后再试');
}
});
} else {
apiTrample.trample(this.courseInfo.id).then(rs => {
this.interactRuning=false;
if (rs.status == 200) {
this.$message.success('已踩');
this.isTrample = true;
this.courseInfo.trampleCount++;
} else {
this.$message.error('踩失败,请稍后再试');
}
});
}
},
statusToContent(status) {
let data = null;
switch (status) {
case 1: {
data = {
text: '未开始',
class: 'catalog-cell-state1'
};
break;
}
case 2: {
data = {
text: '进行中',
class: 'catalog-cell-state2'
};
break;
}
case 9: {
data = {
text: '已完成',
class: 'catalog-cell-state9'
};
break;
}
default:
{
data = {
text: '未开始',
class: 'catalog-cell-state1'
};
}
break;
}
return data;
},
loadAuthorInfo(list, ids) {
//加载作者信息,头像,机构信息
if (ids.length == 0) {
return;
}
apiUser.getByIds(ids).then(res => {
if (res.status == 200) {
list.forEach((item, index) => {
res.result.some(author => {
if (author.aid == item.teacherId) {
item.authorInfo = author;
return true;
} else {
return false;
}
});
});
} else {
//console.log('加载课程信息失败:'+res.error);
//this.$message.error(res.message);
}
});
}
}
};
</script>
<style scoped lang="scss">
.mltit{
// width: 70%;
// width: ;
word-break:break-all;
// line-height: 25px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.catalog-text{
width: 70%;
overflow: hidden;
word-break:break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
height: 40px;
}
.player-box{
position: absolute;
// top: 62px;
// left: 184px;
width: 300px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
height: 187px;
background: rgba(74, 74, 74,.5);
border-radius: 33px;
text-align: center;
padding: 20px;
box-sizing: border-box;
.player-praise{
margin-top: 25px;
display: flex;
// justify-items: center;
justify-content: center;
}
.player-rate{
margin-top: 35px;
}
}
.score {
display: flex;
justify-content: center;
align-items: center;
.el-rate {
display: inline-block;
}
.score-text {
font-size: 28px;
color: #ffb30f;
font-family: 'Arial';
margin-left: 23px;
// font-weight: 600;
}
// margin-bottom: 19px;
.score-no {
color: #ffb30f;
padding: 5px 0;
background: #efefef;
border-radius: 20px;
width: 65px;
font-size: 12px;
font-weight: 600;
text-align: center;
}
}
.portal-content-title {
font-weight: 600;
padding: 10px;
font-size: 22px;
line-height: 40px;
color: #333333;
word-break:break-all;
}
.type-kuang {
color: #666666;
border: 1px solid #666666;
}
.type-click {
color: #ffb30f !important;
border: 1px solid #ffb30f !important;
}
::v-deep .el-rate__icon {
font-size: 22px;
margin-right: 6px;
color: #ff8e00;
transition: 0.3s;
}
.ref-score {
// background: #e4e4e4;
// width: 64px;
// height: 32px;
// border-radius: 17px;
// line-height: 32px;
// // opacity: 0.24;
// color: #000;
// font-size: 14px;
// border: none;
}
.icon-small {
width: 20px;
height: 20px;
line-height: 20px;
vertical-align: middle;
}
.con-audio {
padding: 50px;
text-align: center;
.con-audio-title {
font-size: 16px;
font-weight: 700;
}
.con-audio-player {
padding: 20px 100px;
}
}
.hyper-link {
padding-left: 20px;
text-align: center;
padding-top: 100px;
.hyper-link-row {
padding: 20px;
}
}
.catalog-box {
background: #fff;
// padding: 15px 0px;
// box-shadow: 1px 1px 2px 2px #ededed;
.title {
font-size: 16px;
font-weight: 600;
color: #333333;
padding-left: 20px;
}
}
.collapse-title {
flex: 1 0 90%;
order: 1;
}
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
.course-interact {
height: 54px;
// padding-top: 10px;
// padding-right: 10px;
padding: 0 20px;
line-height: 54px;
background-color: #FFFFFF;
display: flex;
justify-content: space-between;
box-sizing: border-box;
}
.interact-btn {
margin-right: 10px;
}
.uc-badge {
margin-top: 10px;
margin-right: 40px;
}
.cres-list {
list-style-type: decimal;
margin: 0px;
li {
line-height: 30px;
}
.current {
color: #1ea0fa;
}
}
.uc-course {
display: flex;
justify-content: space-around;
border: 1px solid #f0f0f0;
padding: 10px;
.uc-course-img {
width: 200px;
img {
width: 200px;
border: 1px solid #f4f4f5;
}
}
.uc-course-info {
flex: 1;
line-height: 28px;
padding: 0px 10px;
.uc-course-name {
font-size: 18px;
font-weight: 700;
}
.uc-course-text {
color: #747474;
}
}
.uc-course-btns {
width: 150px;
}
}
.catalog-cell-state2 {
height: 24px;
width: 58px;
line-height: 20px;
border: 0px dotted #bed2f8;
padding: 3px 10px;
color: #ff8e00;
font-size: 12px;
border-radius: 6px;
margin-left: 2px;
background: #ffedd6;
}
.catalog-cell-state9 {
height: 24px;
width: 58px;
line-height: 20px;
border: 0px dotted #bed2f8;
padding: 3px 10px;
color: #3e7fff;
font-size: 12px;
border-radius: 6px;
margin-left: 2px;
background: #edf2fd;
// margin-left: 68%;
// background-color: #BED2F8;
}
.catalog-cell-state1 {
height: 24px;
width: 58px;
line-height: 20px;
border: 0px dotted #edf2fd;
border-radius: 6px;
padding: 3px 10px;
color: #ff3e3e;
font-size: 12px;
margin-left: 2px;
background: #fff0f0;
}
.catalog {
height: 500px;
max-width: 500px;
overflow: auto;
.catalog-row {
margin: 0px;
padding: 0px 10px 10px 10px;
.title-type {
width: 36px;
height: 24px;
padding: 2px 5px;
color: #666666;
border: 1px solid #666666;
margin-right: 8px;
}
ul {
padding: 0px;
margin: 0px;
li {
padding: 6px 0;
}
}
.catalog-cell {
line-height: 32px;
cursor: pointer;
list-style: none;
margin: 0px;
padding-left: 20px;
color: #5c5c5c;
}
}
}
.video-div {
position: absolute;
z-index: 999999999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(101, 101, 101, 0.9);
.good {
display: flex;
justify-content: center;
align-items: center;
margin-top: 200px;
div {
line-height: 1;
margin: 0 15px;
.svg-icon {
width: 30px;
height: 30px;
}
}
div:nth-of-type(2) {
.svg-icon {
transform: scaleX(-1);
transform: rotate(180deg);
}
}
// margin-bottom: 50px;
// line-height: 20px;
// .el-link{
// font-size: 30px;
// color: #70a5f4;
// margin: 0 30px;
// }
}
// .score {
// display: flex;
// justify-content: center;
// align-items: center;
// padding-top: 20px
// }
}
::v-deep .el-tag {
background-color: #ecf5ff;
border-color: #409EFF;
display: inline-block;
height: 28px;
padding: 0 10px;
line-height: 28px;
font-size: 12px;
color: #3e7fff;
border-width: 1px;
border-style: solid;
border-radius: 0px;
box-sizing: border-box;
white-space: nowrap;
}
::v-deep .teacher .teacher-avator .teacher-text{
background: none;
border: none;
}
.teacher {
background-color: #ffffff;
display: flex;
border-top: 1px solid #e7e7e7;
padding: 10px 0px;
.teacher-avator {
::v-deep .el-avatar {
width: 68px !important;
height: 68px !important;
border-radius: 0px;
img{
width: 100% !important;
}
}
.teacher-text {
width: 68px;
height: 68px;
div{
img{
width: 68px;
height: 68px;
}
}
// text-align: center;
// line-height: 68px;
// border-radius: 50%;
// color: #73adfe;
// border: 2px solid #73adfe;
// background: #d9e9ff;
}
}
.teacher-info {
flex: 1;
.teacher-name {
padding: 0px 5px 10px 10px;
}
.teacher-remark {
padding: 0px 5px 0 10px;
font-size: 14px;
color: #666666;
line-height: 20px;
}
}
}
.teachers {
background-color: #fff;
margin-top: 10px;
padding: 5px 15px 5px 10px;
.top {
font-size: 16px;
font-weight: 600;
line-height: 50px;
}
}
.breadname {
margin-bottom: 15px;
}
//目录的样式更改
::v-deep .el-collapse-item{
.el-collapse-item__header{
// position: relative;
direction:rtl;
display: flex;
// justify-content;
justify-content: space-between;
// .el-collapse-item__arrow{
// float:right;
// }
// span{
// float:right;
// }
i{
display:none
}
}
}
</style>