Files
learning-system-portal/src/views/portal/course/Micro.vue
2022-11-09 09:17:44 +08:00

1579 lines
54 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>
<div class="xpage-coures-banner">
<portal-header current="course" textColor="#fff" :goSearch="1"></portal-header>
<div class="xcontent">
<div class="banner-crumbs">
<router-link to="/course"><span class="crumbs-first">课程列表</span></router-link>
<span class="crumbs-line"> &gt; </span>
<span class="crumbs-last">课程详情</span>
</div>
<div class="bcourse-title">
<!-- <span>{{courseInfo.name}}</span> -->
<!-- <span>{{courseInfo.summary}}</span> -->
<!-- <span class="bcourse-score">{{toScore(courseInfo.score)}}</span> -->
</div>
</div>
</div>
<div class="portal-content xcontent" style="margin-top: 20px;">
<el-card :body-style="{ padding: '0px', 'min-height': '500px' }">
<el-row class="detail">
<el-col :span="18">
<el-tabs v-model="activeName" @tab-click="changeTab">
<el-tab-pane label="课件" name="courseware">
<div>
<div class="courseware-div" v-if="enrollStutas == 1" style="max-height: 400px;">
<course-image :course="courseInfo" class="courseware-img"></course-image>
</div>
<div class="courseware-div" v-else>
<div v-if="coursewareInfo.content.contentType == 10" style="position: relative;">
<videoPlayer id="myVideoPlayer" :src="blobUrl" style="width: 100%;"
@onPlayerPlaying="onPlayerPlaying"
@onPlayerPlay="onPlayerPlay"
:initTime="videoPlayingTime"
:isDrag="curriculumData.isDrag"
@onPlayerPause="onPlayerPause"
@onFullscreen="onFullscreen"
@onPlayerEnded="onPlayerEnded">
</videoPlayer>
<div class="player-box" v-if="playerBoxShow">
<div class="player-praise">
<div @click="praiseContent" style="cursor: pointer;">
<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')" />
<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')" />
<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="coursewareInfo.content.contentType == 20">
<div class="con-audio">
<div class="con-audio-player">
<audioPlayer :url="fileBaseUrl+curriculumData.url"
:name="coursewareInfo.content.contentName"
@onPlaying="audioPlaying"
@onPlay="audioPlay"
:isDrag="curriculumData.isDrag"
@onPause="audioPause"
@onPlayEnd="audioEnd">
</audioPlayer>
</div>
</div>
</div>
<div v-if="coursewareInfo.content.contentType == 30">
<img :src="fileBaseUrl+coursewareInfo.content.content" alt="图片">
</div>
<div v-if="coursewareInfo.content.contentType == 40">
<div style="padding: 10px;color: #ed0000; " v-if="curCFile.converStatus < 2 && !coursewareInfo.content.content">
<div>此课程内容无法预览请联系管理员</div>
</div>
<div style="padding: 10px;color: #ed0000; " v-if="curCFile.converStatus == 3 && !coursewareInfo.content.content">
此课程内容无法预览请联系管理员
</div>
<pdfPreview :autoScroll="true" v-if="coursewareInfo.content.contentType == 40" :filePath="fileBaseUrl+coursewareInfo.content.content"></pdfPreview>
</div>
<div v-if="coursewareInfo.content.contentType == 41">
<div class="couretitle" style="padding: 20px;text-align: left;" v-html="coursewareInfo.content.content"></div>
</div>
<div v-if="coursewareInfo.content.contentType == 52">
<div class="hyper-link" v-if="conLink.openType==2">
<div class="hyper-link-row">课程内容是外部连接</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;border:0px" border="0" frameborder="0"></iframe>
</div>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane v-if="homeworkInfo.has" :disabled="enrollStutas == 1" label="作业" name="homework">
<homework v-if="studyId!=''" :studyId="studyId" :content="homeworkInfo.content" ></homework>
</el-tab-pane>
<el-tab-pane v-if="examInfo.has" :disabled="enrollStutas == 1" label="考试" name="test">
<exam v-if="studyId!=''" :studyId="studyId" :content="examInfo.content"></exam>
</el-tab-pane>
<el-tab-pane v-if="assessInfo.has" :disabled="enrollStutas == 1" label="评估" name="assess">
<assess v-if="studyId!=''" :studyId="studyId" :content="assessInfo.content"></assess>
</el-tab-pane>
</el-tabs>
<div style="display: flex;justify-content: space-between;padding: 10px;align-items: center;">
<div class="score">
<div v-if="enrollStutas == 1 && !scoreInfo.has">
<div v-if="courseInfo.score">
<el-rate disabled v-model="courseInfo.score"></el-rate>
<span class="score-text">{{toScore(courseInfo.score)}}<span style="font-size: 14px;"></span></span>
</div>
<div v-else class="score-no">未评分</div>
</div>
<div v-if="enrollStutas == 2" style="display: flex;justify-content: center; align-items: center;">
<div v-if="!scoreInfo.has" style="margin-left:10px;cursor: pointer;padding-top: 15px;">
<el-rate v-model="scoreInfo.score" @change="addScore"></el-rate>
</div>
<div v-else style="padding-top: 10px;display: flex;margin-left: 10px">
<div style="padding-top: 5px;">
<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>
<div style="display: flex;align-items: center;padding-top: 15px;">
<div @click="praiseContent" style="cursor: pointer;">
<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>
<span style="margin-left: 5px;color: #666666;font-size: 18px;">{{courseInfo.praises}}</span>
</div>
<div style="margin-left: 15px;cursor: pointer;" @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>
<span style="margin-left: 5px;color: #666666;font-size: 18px;">{{courseInfo.trampleCount}}</span>
</div>
</div>
</div>
</el-col>
<el-col :span="6" class="cont">
<interactBar :readonly="enrollStutas==1" :type="1" :data="courseInfo" :views="false" :praises="false" :comments="false"></interactBar>
<div class="title title-index">{{courseInfo.name}}</div>
<div class="study-count"><span class="num">{{courseInfo.studys}}人学习</span></div>
<div class="label"><el-tag class="label-item" effect="plain">录播课</el-tag></div>
<div class="label" v-if="tags.length >0">
<el-tag class="label-item" effect="plain" v-for="(item, index) in tags" :key="index">{{item}}</el-tag>
</div>
<div v-if="enrollStutas != 2" class="score" style="padding-top: 135px;justify-content: flex-start;">
<div v-if="courseInfo.score">
<el-rate disabled v-model="courseInfo.score"></el-rate>
<span class="score-text">{{toScore(courseInfo.score)}}<span style="font-size: 14px;"></span></span>
</div>
<div v-else class="score-no">未评分</div>
</div>
<img class="detail-img" v-show="!showQrcode && (courseInfo.device == 2 || courseInfo.device == 3)" @click="showQrcode = true" src="../../../assets/images/qr.png" alt="" srcset="">
<div class="qr-code" v-show="showQrcode && ((courseInfo.device == 2 || courseInfo.device == 3))" style="padding-top: 10px;">
<div id="qrcode" ref="qrcode" class="qrcode" @click="showQrcode = false"></div>
</div>
</el-col>
</el-row>
</el-card>
<el-row :gutter="10">
<el-col :span="18">
<div class="el-tab-pane-boxContent" style="background-color: #FFFFFF;padding: 20px;margin-top: 10px;">
<el-tabs v-model="bootTabActive">
<el-tab-pane label="课程介绍" name="info">
<div class="content"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 目标人群</div>
<div class="content-text" >{{courseInfo.forUsers}}</div>
<div class="content"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 课程价值</div>
<div class="content-text">{{courseInfo.value}}</div>
<div class="content"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 详细介绍</div>
<div class="content-text" v-html="courseInfo.summary"></div>
</el-tab-pane>
<el-tab-pane :label="'评论('+commentsTtoal+')'" name="commnets">
<comments v-if="courseInfo.id!=''"
:readonly="enrollStutas==1"
:showTop="false"
@writeTotal="showCommentsTotal"
@success="addCommentSuccess"
@delSuccess="delCommentSuccess"
:obj-type="1"
:to-users="toUsers"
:obj-id="courseInfo.id"
:obj-title="courseInfo.name">
</comments>
</el-tab-pane>
</el-tabs>
</div>
</el-col>
<el-col :span="6">
<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">
<el-avatar v-if="item.avatar !== ''" :src="item.avatar" shape="circle" :size="50"></el-avatar>
<div class="teacher-text" v-else>
<div v-if="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>
</el-col>
</el-row>
</div>
<portal-footer></portal-footer>
</div>
</template>
<script>
import QRCode from 'qrcodejs2';
import { mapGetters,mapActions} from 'vuex';
import portalHeader from "@/components/PortalHeader.vue";
import comments from "@/components/Portal/comments.vue";
import portalFooter from "@/components/PortalFooter.vue";
import interactBar from "@/components/Portal/interactBar.vue";
import apiCourseFile from "@/api/modules/courseFile.js";
import apiCoursePortal from "@/api/modules/coursePortal.js";
import apiUser from '@/api/system/user.js';
import exam from '@/components/Course/exam';
import homework from '@/components/Course/homework';
import assess from '@/components/Course/assess';
import {toScore,courseType, getType, numberToLetter, correctJudgment,userAvatarText} from "@/utils/tools.js";
import apicourseStudy 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 FileUpload from "@/components/FileUpload/index.vue";
import pdfPreview from "@/components/PdfPreview/index.vue";
import { setTimeout } from "timers";
import videoPlayer from '@/components/VideoPlayer/index.vue';
import audioPlayer from '@/components/AudioPlayer/index.vue';
import courseImage from "@/components/Course/courseImage.vue";
import studyUtil from '@/utils/study.js';
import {encrypt} from '@/utils/jsencrypt.js';
import cookies from 'vue-cookies'
export default {
name: "micro",
components: {
portalHeader,
portalFooter,
interactBar,
FileUpload,
comments,
pdfPreview,
videoPlayer,
audioPlayer,
courseImage,
homework,
exam,
assess
},
computed: {
...mapGetters(['resOwnerMap','sysTypeMap','userInfo']),
},
data() {
return {
curCFile:{},
sex:null,
playerBoxShow:false,
userAvatarText,
showQrcode:false,
qrcode: '',
showiframe: false,//用于超连接的
toScore,
correctJudgment:correctJudgment,
show:0,
studyId: "",
tags: [],
numberToLetter: numberToLetter,
fileBaseUrl: process.env.VUE_APP_FILE_BASE_URL,
blobUrl:'',//播放的文件地址新添加采用blob方式
getType: getType,
courseType,
activeName: "courseware",
courseInfo: {
id: "",
type: 10,
name: "",
favorites: 0,
comments: 0,
shares: 0,
praises: 0,
views: 0
},
toUsers:[],//可以@的用户列表
teachers: [],
totalContent: 4, //微课默认是4项
conLink:{openType:1,url:''},//对于超连接的内容
curriculumData:{url:'',isDrag:true,completeSetup:1,setupTage:0,second:0},// 课件内容
coursewareInfo: {
content: {},
finish: false,
process:0,
status:1,
studyItemId: ""
},
homeworkInfo: {
has: false,
content: {},
info: {},
studyItemId: "",
filePath: ""
},
examInfo: {
has: false,
content: {},
info: {},
paper: [],
studyItemId: ""
},
assessInfo: {
has: false,
allowSubmit: true,
content: {},
info: {},
studyItemId: ""
},
enrollStutas: 1, // 1 :未报名2:已报名
dialogVisible: false,
testStart: false,
courseRate: 5,
videoPlayingTime:0,//当前视频的耿入的时间点
appendStartTime: null, //记录追加的开始时间
scoreInfo: {
score: 5,
has: false
},
interactRuning:false,
isPraise: false,
isTrample: false,
bootTabActive:'info',
commentsTtoal:0,
appendHandle:null,//追加时长时间对象
isAppendTime:false,//是否追加学习时长
appentId:'',//当前追加的学习时长的id
appentInterval:30000,//追加学习时间的间隔 30秒加一次
};
},
mounted() {
let id = this.$route.query.id;
this.courseInfo.id = id;
this.showQrimage();
this.$watermark.set(this.userInfo.name+this.userInfo.loginName);
this.loadResOwners();
let $this = this;
//页面只支取一次,所以先直接写在这里面
apiCoursePortal.detail(id,false).then(rs => {
if (rs.status == 200) {
this.courseInfo = rs.result.course;
if(rs.result.course.tags != '') this.tags = rs.result.course.tags.split(",");
this.teachers = rs.result.teachers;
if(rs.result.teachers && rs.result.teachers.length > 0){
let userIds=[];
let ctoUsers=[];
rs.result.teachers.forEach(item=>{
item.avatar = "";
userIds.push(item.teacherId);
ctoUsers.push({aid:item.teacherId,name:item.teacherName,});
})
this.toUsers=ctoUsers;
this.loadAuthorInfo(rs.result.teachers,userIds)
}
this.totalContent = rs.result.contents.length; //计算总内容数
if (!rs.result.course.resOwner3) {
this.courseInfo.resOwner = this.resOwnerName(
rs.result.course.resOwner2
);
} else {
this.courseInfo.resOwner = this.resOwnerName(
rs.result.course.resOwner3
);
}
rs.result.contents.forEach(con => {
if (con.sortIndex == 1) {
$this.coursewareInfo.content = con;
if(con.contentType == 10 || con.contentType == 20) {
if(con.content.startsWith('\{')){
this.curriculumData=JSON.parse(con.content);
}else{
this.curriculumData.url=con.content;
}
//对url进行加密处理
$this.createPlayUrl(con.contentRefId,this.curriculumData.url);
} else if (con.contentType == 40) {
//需要读取pdf的路径
apiCourseFile.detail($this.coursewareInfo.content.contentRefId).then(cfrs=>{
if(cfrs.status==200){
$this.curCFile = cfrs.result;
if(cfrs.result.previewFilePath){
$this.coursewareInfo.content.content=cfrs.result.previewFilePath;
$this.curCFile=2;
}else if(cfrs.result.filePath.indexOf('.pdf')>-1){
$this.coursewareInfo.content.content=cfrs.result.filePath;
$this.curCFile=2;
}
}else{
$this.$message.error('加载pdf课件文件失败');
}
});
}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){
//直接设置完成状态
this.widthOpen(this.conLink.url);
}
}
// //加载课件的学习情况
} else if (con.sortIndex == 2) {
$this.homeworkInfo.content = con;
$this.homeworkInfo.has = true;
//查询作业信息,并显示
} else if (con.sortIndex == 3) {
$this.examInfo.has = true;
$this.examInfo.content = con;
//查询考试信息并显示
//$this.loadExamInfo();
} else if (con.sortIndex == 4) {
$this.assessInfo.has = true;
$this.assessInfo.content = con;
//转化文本为json内容
}
});
//study info
this.loadStudyInfo();
} else {
if(rs.status==204){ //无查看此课程的权限
this.courseInfo.name=rs.result.course.name;
}
this.$message.error(rs.message);
}
});
},
methods: {
createPlayUrl(fid,u){
let nowDate=new Date();
let ctime=parseInt(nowDate.getTime()/1000);
let beforeUrl=parseInt(nowDate.getTime()/1000)+'/'+fid;
let urlSign=encodeURIComponent(encrypt(beforeUrl));
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;
}
},
showQrimage(row){
let urlPre=window.location.protocol+'//'+window.location.host;
// https://u.boe.com/mobile/pages/resource/microDetail?id=963456709515939840
// this.qrcode = this.webBaseUrl+'/mobile/pages/resource/microDetail?id='+this.courseInfo.id;
urlPre='https://u.boe.com/m?returnUrl=https://u.boe.com/mobile/pages/login/loading?returnUrl=';
this.qrcode =urlPre+ '/pages/resource/microDetail?id='+this.courseInfo.id;
this.$nextTick(() => {
this.crateQrcode();
});
},
crateQrcode(){
this.qr = new QRCode('qrcode', {
width: 150,
height: 150, // 高度
text: this.qrcode // 二维码内容
// render: 'canvas' // 设置渲染方式(有两种方式 table和canvas默认是canvas
// background: '#f0f'
// foreground: '#ff0'
});
this.qr._el.title = '';
},
...mapActions({
getResOwnerTree:'resOwner/getResOwnerTree',
loadResOwners:'resOwner/loadResOwners',
getSysTypeTree:'sysType/getSysTypeTree',
loadSysTypes:'sysType/loadSysTypes'
}),
resOwnerName(code){
if(code==''){return '';}
return this.resOwnerMap.get(code);
},
widthOpen(url) {
window.open(this.webBaseUrl+url,'_blank');
},
showCommentsTotal(total){
this.commentsTtoal=total;
},
addCommentSuccess(comm){
this.commentsTtoal++;
},
delCommentSuccess() {
this.commentsTtoal--;
},
saveStudyItem(){ //先保存学习的内容,针对于音视频的内容
if(this.coursewareInfo.finish || this.coursewareInfo.studyItemId) {
return;//已记录学习记录的不再保存
}
let params = {
studyId: this.studyId, //学习id,
courseId: this.courseInfo.id, //课程id,
contentId: this.coursewareInfo.content.id, //内容id,
contentType:this.coursewareInfo.content.contentType, //内容id,
contentName: this.coursewareInfo.content.contentName, //内容名称
progress: 0,
lastStudyTime:0,
status:2,
studyDuration:0,
contentTotal: this.totalContent
};
apiVideoStudy.saveStudyItem(params).then(res=>{
if(res.status == 200){
this.coursewareInfo.studyItemId=res.result.id;
this.coursewareInfo.finish = false;
this.coursewareInfo.status = 2;
this.coursewareInfo.progress = 1;
}else{
console.log("记录学习失败:" + res.message + "" + res.error);
}
});
},
finishStudyItem(){ //设置完成学习的内容,针对于音视频的内容
let params={
itemId:this.coursewareInfo.studyItemId,
studyId:this.studyId,
courseId:this.courseInfo.id,
cnum:this.totalContent
}
apiVideoStudy.finishStudyItem(params).then(res=>{
if(res.status == 200){
this.coursewareInfo.finish = true;
this.coursewareInfo.status = 9;
this.coursewareInfo.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);
//console.log(markDiv,'markDiv');
if(markDiv){
div.removeChild(markDiv);
}
}
},
onPlayerPlay(){
this.playerBoxShow = false;
//console.log("开始播放");
this.isAppendTime=false;
//视频类的内容,开始播放时才会记录完成情况
//2022-05-24修改判断播放的
let $this=this;
//完成类型 completeSetup 0表默认打开后5秒算学完1表按进度2表按时间
//完成值(非默认情况下起作用) setupTage
if(!$this.coursewareInfo.finish){
let completeType=this.curriculumData.completeSetup;
if(completeType==0){
//默认5秒后学习完成.
setTimeout(() => {$this.saveStudyInfo();}, 5000);
}else{
//先记录进行中的学习内容
this.saveStudyItem();
}
}
},
onPlayerPause(){
//console.log("暂停");
},
onPlayerEnded(){
//this.onFullscreen(false);//退出全屏
this.playerBoxShow = true;
this.isAppendTime=true;//开始追加学习时间
//this.saveStudyDuration();//保存添加学习时长
if(!this.coursewareInfo.finish){
this.finishStudyItem();
}
},
onPlayerPlaying(itme){
this.isAppendTime=false;//禁止追加学习时间
this.appendStartTime=null;
//console.log("当前播放11"+itme);
let intTime=parseInt(itme);
//console.log(intTime,'intTime');
this.videoPlayingTime=intTime;
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond){
completeSecond=5;//如果没有就采用默认的时间了
}
if(completeType>0 && !this.coursewareInfo.finish){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let videDuration=this.coursewareInfo.content.duration;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else if(completeType==2){
if(intTime>completeSecond){
this.finishStudyItem();
}
}
}
//以下是每10秒记录一次学习时长
let saveTime=Math.floor(intTime%10);
if(intTime>10 && saveTime==0 && this.coursewareInfo.studyItemId!=''){
//记录播放时间
//console.log('记录播放时间:'+intTime);
let postData={
itemId:this.coursewareInfo.studyItemId,
videoTime:intTime
}
apicourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
audioPlaying(item,currentTime){
let intTime=parseInt(currentTime);//秒
//判断是否完成
let completeType=this.curriculumData.completeSetup;
let completeSecond=this.curriculumData.second;
if(!completeSecond){
completeSecond=5;//如果没有就采用默认的时间了
}
if(completeType>0 && !this.coursewareInfo.finish){ //因为1按进度2按时长都是计算时间所以这里直接大于0处理
if(completeType==1){
let finishPercent=this.curriculumData.setupTage;
let videDuration=this.coursewareInfo.content.duration;
let percent =intTime*100/videDuration;
if(percent>=finishPercent){
this.finishStudyItem();
}
}else if(completeType==2){
if(intTime>=completeSecond){
this.finishStudyItem();
}
}
}
//以下是每5秒记录一次学习时长
let saveTime=Math.floor(intTime%10);
if(intTime>10 && saveTime==0 && this.coursewareInfo.studyItemId!=''){
//记录播放时间
//console.log('记录播放时间:'+intTime);
let postData={
itemId:this.coursewareInfo.studyItemId,
videoTime:intTime
}
apicourseStudy.studyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
})
}
},
audioPlay(){
//console.log("开始播放");
let $this=this;
if (!$this.coursewareInfo.finish) {
let completeType=this.curriculumData.completeSetup;
//console.log(completeType,"completeType");
if(completeType==0){
//默认5秒后学习完成.
setTimeout(() => {$this.saveStudyInfo();}, 5000);
}else{
//先记录进行中的学习内容
this.saveStudyItem();
}
}
},
audioPause(){
//console.log("暂停");
},
audioEnd(){
// this.playerBoxShow = true;
if(!this.coursewareInfo.finish){
this.finishStudyItem();
}
},
changeTab(tab){
this.playerBoxShow = false;
this.saveStudyDuration();//保存一次学习时长,在切换时
let $this = this;
if (tab.name == "homework") {
} else if (tab.name == "test") {
} else if (tab.name == "assess") {
// //console.log('加载评估信息');,评估只会有一个,所以主直接取
// let params = {
// studyId: this.studyId,
// contentId: this.assessInfo.content.id
// };
// apicourseStudy.myAssessList(params).then(res => {
// if (res.status == 200) {
// if (res.result.length > 0) {
// this.assessInfo.allowSubmit = false;
// this.assessInfo.info = JSON.parse(res.result[0].asContent);
// }
// } else {
// this.$message.error(res.message);
// }
// });
} else {
//在课件页面,记录开始时间
//对于视频类的,是在点击开始播放后执行的
if(this.coursewareInfo.content.contentType>10){
this.isAppendTime=true;
this.appendStudyTime(false);
if(!this.coursewareInfo.finish){
setTimeout(() => {$this.saveStudyInfo();}, 5000);
}
}else{
this.isAppendTime=false;
}
}
},
saveStudyInfo() {
//记录课件学习信息
if (this.activeName != "courseware") {
//只有在课件页面停留超过5秒才会记录
return;
}
if (this.coursewareInfo.finish) {
return;
}
let params = {
studyId: this.studyId, //学习id,
courseId: this.coursewareInfo.content.courseId, //课程id,
contentId: this.coursewareInfo.content.id, //内容id,
contentType:this.coursewareInfo.content.contentType, //内容id,
contentName: this.coursewareInfo.content.contentName, //内容名称
progress: 100,
status:9,
contentTotal: this.totalContent
};
apicourseStudy.studyContent(params).then(res => {
if (res.status == 200) {
this.coursewareInfo.studyItemId=res.result;
this.coursewareInfo.finish = true; //课件内容已学习,记录状态
} 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.coursewareInfo.content.id,
studyInfo:
this.courseInfo.name +
"-" +
this.coursewareInfo.content.contentName,
duration: duration
};
apicourseStudy.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.isAppendTime){
//如果不追加时间把追加开始时间设置为null
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.coursewareInfo.content.id,
studyInfo:
this.courseInfo.name +
"-" +
this.coursewareInfo.content.contentName,
duration: sen
};
apicourseStudy.appendStudyTime(postData).then(rs => {
if (rs.status == 200){
$this.appentId=rs.result;
$this.appendStartTime = new Date(); //重置开始时间
studyUtil.clearStudyDuration();//清除本地存储
} else {
console.log(rs.message);
}
});
}
}else{
$this.appendStartTime = new Date(); //重置开始时间
studyUtil.setStudyDuration(duration);//添加到本地存储中
}
this.appendHandle=setTimeout(function() {$this.appendStudyTime();},$this.appentInterval);
},
loadStudyInfo() {
//获取学习信息
let $this = this;
this.loadScorePraiseAndTrample();
apicourseStudy.studyInfo(this.courseInfo.id).then(res => {
if (res.status == 200) {
res.result.signup ? (this.enrollStutas = 2) : (this.enrollStutas = 1);
if(res.result.signup) {
//this.bootTabActive = 'commnets';//系统自动报名,这里不进行切换了
this.studyId = res.result.studyId; //设置学习id
//需要判断此内容是否已学习完成,如果已学习完成,不需要再请不说了
res.result.contents.forEach(con => {
if (con.contentId == $this.coursewareInfo.content.id) {
$this.coursewareInfo.studyItemId=con.id;
$this.coursewareInfo.status=con.status;
$this.coursewareInfo.progress=con.progress;
if(con.contentType==10 || con.contentType==20){
if(con.progress==100 || con.status==9){
$this.coursewareInfo.finish = true;
}else{
$this.coursewareInfo.finish = false;
}
}else{
$this.coursewareInfo.finish = true; //课件已学习
}
if(con.lastStudyTime){
//如果上次课件已经播放完成,此处应该是$this.coursewareInfo.content.duration
//也就是从头开开始
$this.videoPlayingTime=con.lastStudyTime;
}
//console.log()
}else if (con.contentId == $this.homeworkInfo.content.id) {
$this.homeworkInfo.studyItemId = con.id;
}else if (con.contentId ==$this.examInfo.content.id) {
$this.examInfo.studyItemId = con.id;
}else if (con.contentId == $this.assessInfo.content.id) {
$this.assessInfo.studyItemId = con.id;
}
});
//存储上一次学习时长,主要用于上次未存储的学习时长
this.saveStudyDuration();
if(!$this.coursewareInfo.finish && $this.coursewareInfo.content.contentType>20) {
//未完居并且类型不是视频的直接设计5秒后学习完成
setTimeout(() => {$this.saveStudyInfo();}, 5000); //5秒后记录学习
//开始记录学习时长
$this.isAppendTime=true;
$this.appendStudyTime(false);
}
}else{
//signup 没有报名的情况下,直接报名
this.submitEnroll();
}
} else {
this.$message.error(res.message);
}
});
},
submitEnroll() { //提交报名
let pamars = {
courseId: this.courseInfo.id,
courseName: this.courseInfo.name,
courseType: this.courseInfo.type,
signType: 1,
signInfo: ""
};
let $this = this;
apicourseStudy.signup(pamars).then(res => {
if (res.status == 200) {
//this.$message({ type: "success", message: "报名成功" });
this.enrollStutas = 2;
this.studyId=res.result.studyId;//设置学习的ID
//this.loadStudyInfo();
if($this.coursewareInfo.content.contentType>20){
this.isAppendTime=true;
this.appendStudyTime(false); //报名成功记录开始时间
//报名成功后就直接记录课件学习情况5秒后
setTimeout(() => {$this.saveStudyInfo();}, 5000);
}else{
//对于视频类的处理,用户手动点击播放,不做处理
}
} else {
this.$message.error(res.message);
}
});
},
loadScorePraiseAndTrample() {
//加载是否打过分
//if(this.enrollStutas>1){
apiCourseGrade.has(this.courseInfo.id).then(rs => {
if (rs.status == 200 && rs.result) {
this.scoreInfo.has = true;
}
});
//}
apiPraises.has(1, this.courseInfo.id).then(rs => {
if (rs.status == 200 && rs.result) {
this.isPraise = true;
}
});
apiTrample.has(this.courseInfo.id).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.enrollStutas==1){
this.$message.error("报名学习之后才可以点赞");
return;
}
if(this.isTrample){
this.$message.error("您已踩过了,不能再赞了");
return;
}
if(this.interactRuning){
return;
}
this.interactRuning=true;
let postData = {
objType: 1,
objId: this.courseInfo.id,
title: this.courseInfo.name
};
if(this.isPraise){
apiPraises.remove(1,this.courseInfo.id).then(res=>{
this.interactRuning=false;
if (res.status == 200){
if(this.courseInfo.praises>0){
this.courseInfo.praises--;
}
this.$message.info("已取消点赞");
this.isPraise = false;
} else {
this.$message.error("取消点赞失败,请稍后再试");
}
});
}else{
apiPraises.save(postData).then(rs => {
this.interactRuning=false;
if (rs.status == 200) {
this.courseInfo.praises++;
this.$message.success("点赞成功");
this.isPraise = true;
} else {
this.$message.error("点赞失败,请稍后再试");
}
});
}
},
treadContent() {
if(this.enrollStutas==1){
this.$message.error("只有报名学习后才可以踩");
return;
}
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) {
if(this.courseInfo.trampleCount>0){
this.courseInfo.trampleCount--;
}
this.$message.info("已取消踩");
this.isTrample = false;
} else {
this.$message.error("取消失败,请稍后再试");
}
});
}else{
apiTrample.trample(this.courseInfo.id).then(rs => {
this.interactRuning=false;
if (rs.status == 200) {
this.courseInfo.trampleCount++;
this.$message.success("已踩");
this.isTrample = true;
} else {
this.$message.error("踩失败,请稍后再试");
}
});
}
},
loadAuthorInfo(list,ids){ //加载作者信息,头像,机构信息
if(ids.length==0){
return;
}
apiUser.getByIds(ids).then(res=>{
if(res.status==200){
list.forEach((item,index)=>{
res.result.some(author=>{
if(author.aid==item.teacherId){
if(author.avatar){
item.avatar=this.fileBaseUrl + author.avatar;
}
this.sex = author.sex
return true;
}else{
return false;
}
})
});
}else{
//console.log('加载课程信息失败:'+res.error);
//this.$message.error(res.message);
}
});
},
}
};
</script>
<style scoped lang="scss" scoped>
.couretitle{
word-break: break-all;
}
::v-deep .teacher .teacher-avator .teacher-text {
background: none;
border: none;
}
.player-box{
position: absolute;
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: 39px;
}
}
::v-deep .el-tabs__nav-wrap::after {
background-color: #fff;
}
::v-deep .el-tabs__nav-wrap::after {
background-color: #fff;
}
.qrcode{
display: inline-block;
img {
width: 200px;
height: 200px;
background-color: #fff; //设置白色背景色
padding: 6px; // 利用padding的特性挤出白边
box-sizing: border-box;
}
}
.ref-score{
}
.portal-content ::v-deep .el-rate__icon{
font-size: 24px !important;
}
::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;
}
.content{
padding: 10px 0;
font-size: 18px;
color: #343434;
img{
width: 18px;
}
}
.content-text{
margin: 10px 0;
font-size: 14px;
text-indent: 2em;
color: #666666;
word-break:break-all;
}
::v-deep .el-tabs__item.is-active {
color: #409EFF;
font-size: 18px;
}
.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;
}
}
.red{
background: red;
background-image: linear-gradient(to bottom right, rgb(245, 30, 30) , rgb(241, 227, 21));
}
.paper-item-answer{
line-height: 30px;
border-bottom: 1px solid #ccc;
margin-bottom: 10px;
}
.paper-item-opts{
.el-radio {
display: block;
}
.el-checkbox {
display: block;
}
}
.detail {
background-color: #fff;
padding: 5px 20px 10px 20px;
position: relative;
.detail-img{
cursor: pointer;
position: absolute;
bottom: 0;
right: 0;
}
.courseware-div {
border: 1px solid #f0f0f0;
min-height: 400px;
// width: 876px;
// font-size: 30px;
text-align: center;
// line-height: 100px;
position: relative;
.courseware-img {
vertical-align: middle;
width: 100%;
height: 100%;
}
.courseware-enroll-btn {
position: absolute;
width: 270px;
height: 68px;
font-size: 22px;
left: 230px;
top: 165px;
opacity: 0.3;
background: #000000;
border-radius: 21px;
}
.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);
}
}
}
}
}
.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;
}
.score-no{
color: #FFB30F;
padding: 5px 0;
background: #efefef;
border-radius: 20px;
width: 65px;
font-size: 12px;
font-weight: 600;
text-align: center;
}
}
.homework-div {
border: 1px solid #bcbcbc;
min-height: 500px;
padding: 20px;
font-size: 14px;
.homework-title {
font-weight: 600;
margin-bottom: 10px;
}
.homework-content {
color: #666;
margin-bottom: 10px;
}
}
.test-div {
border: 1px solid #bcbcbc;
min-height: 500px;
padding: 20px;
font-size: 16px;
.test-info {
margin-bottom: 10px;
.el-radio {
display: block;
}
}
}
.assess-div {
border: 1px solid #bcbcbc;
min-height: 500px;
padding: 20px;
font-size: 14px;
.assess-info {
margin-bottom: 10px;
}
}
.cont {
padding: 10px 25px 25px 25px;
height: 540px;
.title {
font-size: 20px;
font-weight: 600;
line-height: 36px;
word-break:break-all;
}
.course-info-tools-btns {
::v-deep .interact-bar-btns {
justify-content: flex-start !important;
}
.course-info-tools-btn {
margin: 0 15px 0 0;
}
margin-bottom: 15px;
}
.label {
margin-bottom: 15px;
.label-item {
margin-right: 5px;
margin-bottom: 5px;
}
}
.keyword {
margin-bottom: 15px;
.label-item {
margin-right: 5px;
}
}
.study-count {
padding: 20px 0;
.num {
color: #444444;
font-size: 16px;
}
margin-bottom: 15px;
}
.btn-div {
margin-top: 30px;
.btn{
border-radius: 0px;
font-size: 16px;
}
}
.qr-code {
cursor: pointer;
text-align: right;
position: absolute;
bottom: 0;
right: 4px;
div {
text-align: center;
font-size: 14px;
}
}
.view-summary {
position: absolute;
margin-bottom: 10px;
margin-left: 18px;
}
}
}
.summary-div {
.summary-content {
font-size: 14px;
line-height: 25px;
}
}
.info {
background-color: #fff;
margin-top: 20px;
padding: 0 10px;
.content {
color: #666;
line-height: 25px;
text-indent: 2em;
padding: 5px 10px;
}
.pinglun-div {
background-color: #fff;
padding: 0px 20px 10px 20px;
.title {
font-size: 16px;
font-weight: 600;
line-height: 50px;
border-bottom: 1px solid #dfdfdf;
.tip {
color: #666;
font-size: 12px;
margin: 0 10px;
}
}
.submit-div {
margin: 15px 0;
}
.bottom {
text-align: right;
}
.data {
margin-top: 10px;
background-color: #fff;
padding: 5px 20px 10px 20px;
.data-item {
border-bottom: 1px solid #dfdfdf;
margin-top: 10px;
.top {
font-size: 18px;
font-weight: 600;
span {
font-size: 14px;
color: #666;
font-weight: normal;
}
}
.text {
margin: 15px 0 5px 0;
padding-left: 40px;
line-height: 35px;
}
.huifu {
padding-left: 40px;
padding-bottom: 10px;
border-bottom: 1px solid #dfdfdf;
}
.result-div {
padding-left: 40px;
padding-top: 10px;
.top {
font-size: 16px;
}
}
.up-div {
padding: 0 15px;
.up-btn {
padding: 8px 20px;
color: #000;
}
}
img {
margin-right: 10px;
width: 30px;
border: 1px solid #eee;
border-radius: 50%;
vertical-align: middle;
}
}
}
}
}
::v-deep .el-tabs__header{
.el-tabs__item{
font-size: 15px;
}
.is-active{
font-size: 16px;
font-weight: 600;
}
}
.teacher {
background-color: #ffffff;
display: flex;
border-top: 1px solid #e7e7e7;
padding: 10px 0px;
// .teacher-avator {
// }
.teacher-info {
flex: 1;
.teacher-name {
padding: 0px 5px 10px 10px;
}
.teacher-remark {
padding: 0px 5px 0px 10px;
font-size: 12px;
color: #797979;
}
}
}
.teachers {
background-color: #fff;
margin-top: 10px;
padding: 5px 15px 5px 10px;
.top {
font-size: 16px;
font-weight: 600;
line-height: 50px;
}
div{
img{
width: 68px;
height: 68px;
}
}
}
</style>
<style scoped>
.assessRadio1 /deep/ .el-radio-button__inner {
padding-left: 36px;
padding-right: 36px;
}
</style>