Files
learning-system-portal/src/views/study/coursenew.vue
2025-03-31 19:13:55 +08:00

2473 lines
87 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 style="margin: 0px 80px;">
<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" v-if="courseInfo.score>0">{{toScore(courseInfo.score)}} </span>
<span class="bcourse-score" v-else>无评分</span>
-->
</div>
</div>
</div>
<div class="course-content xcontent">
<div class="course-playbox" ref="coursePlayerBox" id="id_course_player_box">
<div class="course-player" ref="coursePlayer" id="id_course_player">
<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 ref="myVideoPlayer" id="myVideoPlayer" @progress="progress" :src="blobUrl" :blobId="blobId" @onPlayerPlaying="onPlayerPlaying"
:initTime="contentData.lastStudyTime" :notePlay="notePlay" @onPlayerPlay="onPlayerPlay"
:isDrag="curriculumData.isDrag" @onFullscreen="onFullscreen" @onPlayerPause="onPlayerPause"
@onPlayerEnded="onPlayerEnded" :isCrowd="isCrowd" @onTimeUpdate="handleAudioTimeUpdate"></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="blobUrl" :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 == 50" style="min-height: 500px;">
<iframe v-if="scormUrl" :src="scormUrl" frameborder="0" border="0px" style="width:100%;height:500px;border:0px;"></iframe>
</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 @submit="homeWorkSubmit" v-if="resType == 60 && studyId != ''" :studyId="studyId" :content="contentData"></homework>
</div>
<div v-if="resType == 61">
<exam @startTest="startTest" 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;padding-top:18px">
<!-- <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: 16px;">
<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: 18px;"></span>
</div>
</div>
</div>
<div style="display: flex;justify-content: flex-end;cursor: pointer;padding-top: 5px;">
<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: 20px;" @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 style="margin-left: 6px;">
<interactBar :size="16" :type="1" :aid="courseInfo.sysCreateAid" :data="courseInfo" :praises="false" :favorites="true" :shares="true" :comments="false" :views="false"></interactBar>
</div>
</div>
</div>
</div>
</div>
<div class="course-control">
<div class="control-tab" v-if="contentList.length>0" >
<div v-if="contentList.length>1" @click="heartabone" :class="tab == 1 ? 'control-tab-active' : ' '">
<i class="el-icon-reading" style="margin-right:9px;margin-left:9px"></i>课程单元
</div>
<div @click="heartabtwo" :class="tab == 2 ? 'control-tab-active' : ' '">
<i class="el-icon-edit" style="margin-right:9px;margin-left:9px"></i>我的笔记
</div>
</div>
<!-- 课程单元 -->
<div class="course-units" v-if="tab == 1">
<div :style="`height: ${controlHeight}px;overflow-y: auto;`">
<div class="catalog" v-if="courseInfo.type == 20">
<div v-for="(item, index) in catalogTree" :key="index" :name="index">
<el-menu
ref="menu"
:default-openeds="defaultOpeneds"
:default-active="activeId"
:unique-opened="true"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose">
<el-submenu :index="item.section.id">
<template slot="title">
<div style="display: flex;justify-content: space-between;">
<div style="width: 240px;font-weight: 700;font-size: 16px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;" :title="item.section.name">{{item.section.name}}</div>
<div style="margin-right: 23px;font-weight: 700;font-size: 16px;">({{ item.children.filter(item=>item.status == 9).length }}/{{ item.children.length }})</div>
</div>
</template>
<el-menu-item-group v-for="(ele, i) in item.children" :key="i">
<div class="units-info" :class="{'units-active':contentData.id == ele.id}" @click="showRes(ele,i,index,item)">
<el-menu-item :index="ele.id" style="padding: 0;padding-left: 10px;">
<div style="display: flex;justify-content: space-between;">
<div style="width: 200px;font-size: 16px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;" :title="ele.contentName">{{i+1}}. {{ ele.contentName }}</div>
<div>
<span v-if="contentData.id == ele.id" style="color: #387DF7;font-size: 14px;margin-right: 4px;">学习中</span>
<!-- <img v-if="contentData.id == ele.id" :src="`${webBaseUrl}/images/playicon.png`" alt=""> -->
<img v-if="contentData.id == ele.id && ele.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/over.png" alt="">
<img v-if="contentData.id == ele.id && ele.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/nowNot.png" alt="">
<img v-if="contentData.id == ele.id && (ele.status != 9&&ele.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/ban1.png" alt="">
<img v-if="contentData.id != ele.id && ele.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/notNew.png" alt="">
<img v-if="contentData.id != ele.id && ele.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/not.png" alt="">
<img v-if="contentData.id != ele.id && (ele.status != 9&&ele.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/newBan.png" alt="">
</div>
</div>
</el-menu-item>
</div>
</el-menu-item-group>
</el-submenu>
</el-menu>
</div>
<!-- <div v-for="(item, index) in catalogTree" :key="index" :name="index">
<div style="margin: 10px 0px;font-weight: 700;">{{item.section.name}}</div>
<div class="units-info" :class="{'units-active':contentData.id == ele.id}" v-for="(ele, i) in item.children" :key="i" @click="showRes(ele,i,index)">
<img v-if="contentData.id == ele.id" :src="`${webBaseUrl}/images/playicon.png`" alt=""> {{i+1}}.
<span>{{ ele.contentName }}</span>
</div>
</div> -->
</div>
<div v-else class="catalog">
<!-- contentList -->
<div class="units-info" style="display: flex;justify-content: space-between" v-for="(list, index) in contentList" :key="index" :name="index" @click="showRes(list,-1,index)" :class="{'units-active':contentData.id == list.id}">
<!-- <div class="units-info" :class="{'units-active':contentData.id == ele.id}" @click="showRes(ele,i,index)" v-for="(ele, i) in item.children" :key="i"> -->
<!-- <img v-if="contentData.id == list.id" :src="`${webBaseUrl}/images/playicon.png`" alt=""> -->
<div style="max-width: 193px;;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">
{{index+1}}.{{ list.contentName }}
</div>
<div style="margin-left: 5px">
<span v-if="contentData.id == list.id" style="color: #387DF7;font-size: 14px;margin-right: 4px;">学习中</span>
<img v-if="contentData.id == list.id && list.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/over.png" alt="">
<img v-if="contentData.id == list.id && list.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/nowNot.png" alt="">
<img v-if="contentData.id == list.id && (list.status != 9&&list.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/ban1.png" alt="">
<img v-if="contentData.id != list.id && list.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/notNew.png" alt="">
<img v-if="contentData.id != list.id && list.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/not.png" alt="">
<img v-if="contentData.id != list.id && (list.status != 9&&list.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/newBan.png" alt="">
</div>
<!-- </div> -->
</div>
</div>
</div>
</div>
<!-- 我的笔记 -->
<div class="mynote" v-show="tab == 2">
<my-note ref="mynote" :height="controlHeight" @change="noteChange" :data="courseInfo" @videoLocation="videoLocation" @onPlayVideo="onPlayVideo"
:score="courseInfo.score"></my-note>
</div>
</div>
</div>
<div class="course-infobox">
<div class="course-info">
<div style="background-color: #fff;">
<div class="course-info-tab">
<div @click="coutab(1)" :class="courestab == 1? 'course-info-tab-active' : ''">内容简介<span class=""></span> </div>
<div @click="coutab(2)" :class="courestab == 2? 'course-info-tab-active' : ''">课程评论<span class=""></span> </div>
<div @click="coutab(3)" :class="courestab == 3? 'course-info-tab-active' : ''">课程笔记<span class=""></span> </div>
</div>
<div v-show="courestab==1" style="margin-left:17px;padding-top: 20px;">
<div style="padding: 30px;">
<div class="course-info-row"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 目标人群<div class="course-info-text">{{courseInfo.forUsers}}</div></div>
<div class="course-info-row"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 课程价值<div class="course-info-text">{{courseInfo.value}}</div></div>
<div class="course-info-row"><img src="@/assets/images/icon/remark-iocn.png" alt="" srcset=""> 详细介绍<div class="course-info-text" v-html="courseInfo.summary"></div></div>
</div>
</div>
<div v-show="courestab==2" class="coures-comments" style="margin-left:17px">
<comments v-if="courseInfo.id && courseInfo.id != ''" :obj-type="1" :obj-id="courseInfo.id" :toUsers="toUsers"></comments>
</div>
<div v-show="courestab==3" class="coures-note">
<note-comments :key="timer" v-if="courseInfo.id && courseInfo.id != ''" :obj-type="6" :obj-id="courseInfo.id" :name="courseInfo.name"></note-comments>
</div>
</div>
</div>
<div class="course-teacher">
<div class="cteacher-top">
<div class="cteacher-top"><img width="100%" style="vertical-align: top;" height="10px" src="../../../public/images/tearch-top.png" alt=""></div>
<div class="cteacher-top-title">课程讲师</div>
</div>
<div class="cteacher-list">
<div class="teacher" v-for="(item, idx) in teachers" :key="idx">
<div class="teacher-avator" @click="toUserHome(item)" title="点击进入他的主页">
<!-- <div class="teacher-text" v-if="item.authorInfo.avatar == ''">{{userAvatarText(item.teacherName)}}</div> -->
<div v-if="item.authorInfo.avatar !== ''">
<el-avatar :src="fileBaseUrl + item.authorInfo.avatar" shape="circle" :size="50"></el-avatar>
</div>
<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">
<span> {{ item.teacherName }}</span>
<!-- <span style="font-size: 12px; color:#666666 ;">( {{cutOrgNamePath(item.authorInfo.orgInfo)}} )</span> -->
</div>
<!-- <div class="teacher-remark" v-html="item.authorInfo.sign"></div> -->
<div v-if="item.teacherType === 1 " class="teacher-remark">{{cutOrgNamePath(item.authorInfo.orgInfo)}}</div>
<div v-else>{{item.supplier}}</div>
</div>
<div style="padding-top:15px;width:70px;">
<followButton v-if="item.teacherName!=='BOE教师'" :auto="true" size="small" :aid="item.teacherId"></followButton>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <div><portal-footer></portal-footer></div> -->
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import followButton from "@/components/Follow/button.vue";
import portalHeader from "@/components/PortalHeader.vue";
import portalFooter from "@/components/PortalFooter.vue";
import comments from "@/components/Portal/comments.vue";
import noteComments from "@/components/Portal/noteComment.vue";
import interactBar from "@/components/Portal/interactBar.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';
import apiStat from '@/api/phase2/stat.js';
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 apiUser from '@/api/system/user.js';
import apiCourseFile from '@/api/modules/courseFile.js';
import {
resListMap,
resOwnerListMap,
courseType,
getType,
toScore,
cutOrgNamePath,
userAvatarText
} from '@/utils/tools.js';
import pdfPreview from '@/components/PdfPreview/index.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 myNote from '../../components/Course/myNote.vue';
import apiFollow from "@/api/phase2/userfollow.js";
import apiMessage from '@/api/system/message.js'
// import Vue from 'vue';
// Vue.forceUpdate();
export default {
name: "atticle",
components: {
courseImage,
portalHeader,
hyperLink,
comments,
homework,
exam,
interactBar,
assess,
pdfPreview,
audioPlayer,
videoPlayer,
myNote,
noteComments,
portalFooter,
followButton
},
data() {
return {
tentative: false,
isContentTypeTwo: null,
isContentType: null,
activeId: '',
isFalse: false,
defaultOpeneds: [],
sendEventProgress: 0,
trueFalse: true,
audiences:'',
isCrowd:false,
cutOrgNamePath,
scormUrl:'',//当前播放的scormUrl
loading:false,
controlHeight:400,//左边控制区域的内容高度
timer: '',
notePlay: null,
intTimeNote: '',
courestab: 2,//默认是课程评论
curCFile: {
converStatus: 4,
},
radio: '',
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: this.$xpage.constants.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, //追加学习时长的timeout句柄
isAppendTime: false, //是否追加学习时长
appentId: '', //当前追加的学习时长的id,此字段已经不再使用
appentInterval: 15, //追加学习时间的间隔 5秒加一次
handleTimeout: null,
completed: [],
tab: 1,
notetab: 1,
localTimeKey:'boeu-study-time' ,//本地存储的学习时长的key json格式
localTimeValue:0,//计算的时间
appendStudyOtherHandle:null,
cumulativeDuration:0, //非音频累计时长
maxDuration:0, //非音频最大时长
defaultMaxTime:1800, //非音频默认最大时间
}
},
mounted() {
// 增加的用户受众id
let localKey = "user_" + this.userInfo.sysId + "_gids";
let hasIds = sessionStorage.getItem(localKey);
this.audiences = hasIds ?? ''
this.$watermark.set(this.userInfo.name + this.userInfo.loginName);
this.courseId = this.$route.query.id;
this.initContentId = this.$route.query.contentId;
this.stopStudyTime();//先关闭
this.cleanAppendTime();//
this.loadData();
//console.log(this.$xpage.constants.fileBaseUrl,'this.$xpage.constants.fileBaseUrl');
},
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);
});
// console.log(treeList,'treeList')
return treeList;
}
},
destroyed(){
this.cleanAppendTime();
this.stopStudyTime();
},
methods: {
handleOpen(key,path){
// console.log(key,path,'handleOpen')
if(this.isFalse){
this.defaultOpeneds = [key]
}
this.isFalse = false
},
handleClose(key,path){
// console.log(key,path,'handleClose')
},
toUserHome(tea){
this.$router.push({path:this.$xpage.getHomePath(tea.teacherId)})
},
noteChange(){
//视频点定位,直接到播放的视频位置
this.timer = new Date().getTime()
},
//清空追加学习时长事件
cleanAppendTime(){
if(this.appendStudyOtherHandle){
window.clearTimeout(this.appendStudyOtherHandle);
}
},
//非音视频课学习时长的增加,每一分钟保存一次
appendStudyOtherTime() {
//console.log('开始追加学习时长',this.isAppendTime);
if (this.studyId == '') {
return;
}
if (!this.contentData.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.sendStudyOtherTime(totalTime);
//递归调用
$this.appendStudyOtherTime();
}else{
clearTimeout(this.appendStudyOtherHandle);
$this.cumulativeDuration = 0;
$this.maxDuration = 0;
}
}, 1000*60);
},
sendStudyOtherTime(totalTime){
//静默处理
apiStat.sendEvent({
"key": "StudyCourseOther",//课程学习的key
"title": "非音视频课内容",//事件的标题
"parameters":"second:" + totalTime,//second:value 本次的学习时长
"content": "学习课程",//事件的内容
"objId": this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"page",
"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);
}
});
},
//笔记组件触发,播放指定时间
onPlayVideo(contentId,time){
//这里需要根据contentId,是否切换到对应的内容的视频的时间
//如果 contentId已经不存在需要提示
console.log(contentId,this.contentData.id,'两个内容id');
let $this=this;
if(this.contentData.id==contentId){
this.onPlayerPause()
//this.audioPause();
this.contentData.lastStudyTime=time;
//this.onPlayerPlay();
setTimeout(() => {
$this.$refs.myVideoPlayer.startPlay(time);
}, 10)
console.log('开始播放1');
}else{
//通过contentId
let toResContent=null;
this.contentList.forEach(c => {
if(c.id==contentId){
c.lastStudyTime=time;
toResContent=c;
}
});
if(toResContent){
this.changePlayRes(toResContent);
//this.onPlayerPlay();
setTimeout(() => {
$this.$refs.myVideoPlayer.startPlay(time);
}, 10)
console.log('开始播放2');
}else{
this.$message.error('资源已不存在或更换过,已无法定位');
}
}
this.playerBoxShow = false;
//this.changePlayRes(r);
// this.playerBoxShow = false;
// this.notePlay = null;
// let $this=this;
// setTimeout(() => {
// $this.notePlay = time;
// }, 500)
},
//笔记组件触发,记录当前播放时间
videoLocation() {
//this.$store.dispatch("SetIntTimeNote", this.intTimeNote);
//console.log(this.contentData.id+'='+this.intTimeNote,'设置视频播放时间')
this.$refs.mynote.setVideoTime(this.contentData.id,this.intTimeNote);
},
coutab(n) {
this.courestab =n;
},
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.contentData.id:',this.contentData.id)
this.blobId = this.contentData.id
//console.log(this.blobUrl,'this.blobUrl');
},
widthOpen(url) {
window.open(url, '_blank');
},
//替换播放区域
changePlayRes(r,item){
this.tentative = false;
if(this.appendStudyOtherHandle!=null){
window.clearTimeout(this.appendStudyOtherHandle);
}
this.playerBoxShow = false;
//显示内容部分
this.$refs.mynote.showVideoTimeBtn(false);
let $this = this;
this.resType = r.contentType;
this.contentData = r;
this.activeId = this.contentData.id
if(item){
this.isFalse = true
this.handleOpen(item.section.id,[item.section.id])
}
this.contentData.name = this.courseInfo.name;
this.saveStudyDuration();
if (r.contentType == 10 || r.contentType == 20) {
this.trueFalse = true
if (r.content.startsWith('\{')) {
this.curriculumData = JSON.parse(r.content);
} else {
this.curriculumData.url = r.content;
}
this.$refs.mynote.showVideoTimeBtn(true);
//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==50){ //scorm
this.scormUrl='';
apiCourseFile.detail(r.contentRefId).then(cfrs => {
if(cfrs.status==200){
this.curCFile = cfrs.result;
//this.scormUrl=cfrs
let pars='?mode=normal&r='+Math.random();
pars+='&scormId='+this.curCFile.id;
pars+='&courseId='+this.courseId;
pars+='&contentId='+r.id;
pars+='&studentId='+this.userInfo.aid;
pars+='&studentName='+encodeURIComponent(this.userInfo.name);
pars+='&lmsId='+this.studyId;
pars+='&scoId=';//不指定scorm模块自动根据学习记录定位
let urlPre=window.location.protocol;
let configUrl=process.env.VUE_APP_SCORM_URL;
configUrl=urlPre+configUrl.substring(configUrl.indexOf(':')+1);
this.scormUrl=configUrl+pars;//播放的首页
}
});
}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(r.contentType != 61&&r.contentType != 20 && r.contentType != 10){
setTimeout(() => {
this.isContentTypeTwo = r.contentType
$this.isShowTime()
}, 2000);
}
}
//以下是学习记录,50是scorm项目
if (this.contentData.contentType > 20 && this.contentData.contentType !== 50) { //非视频类的
//用户的学习时长,非音视频课程学习,单独的处理
this.isAppendTime = false;
this.appendStudyOtherHandle = setTimeout(function() {
// 开始之前把响应式清空
$this.maxDuration = 0;
$this.cumulativeDuration = 0;
// 没有设置默认时长三十分钟,
$this.maxDuration = r.duration !== 0 ? r.duration * 2 : $this.defaultMaxTime;
$this.$store.dispatch("userTrigger", {
"key": "StudyCourseOther",//课程学习的key
"title": "非音视频课内容",//事件的标题
"parameters":"second:15",//second:value 本次的学习时长
"content": "学习课程",//事件的内容
"objId": $this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"page",
"objInfo": ""+$this.courseInfo.name,
"aid":$this.userInfo.aid, //当前登录人的id
"aname":$this.userInfo.name,//当前人的姓名
"status": 1 //状态
});
$this.appendStudyOtherTime();
}, 15000); //非音视频课程学习,十五秒后记录
//this.appendStudyTime();
this.isContentType = this.contentData.contentType
if (this.contentData.contentType != 50) {
this.handleTimeout = setTimeout(function(){
$this.saveStudyInfo();
}, 5000); //5秒后记录学习完成
}else{
//scorm课件不记录完成情况由播放回调记录完成情况
//当前先保存学习记录,未学习状态
this.saveScormStudy();
}
}
this.$nextTick(function(){
if(this.contentData.progressVideo){
this.$refs.myVideoPlayer.updateProgressByClickBar2(this.contentData.lastStudyTime,this.contentData.progressVideo);
// $this.notePlay = this.contentData.lastStudyTime;
}
//let h0=document.getElementById('id_course_player').offsetHeight;
let h=$this.$refs.coursePlayer.offsetHeight;
//let h1=$this.$refs.coursePlayer.clientHeight;
///console.log(h0,h,$this.controlHeight,'$this.controlHeight');
//解决获取高度不正的问题
if(h>400 && h<500){
h=h+40;
}else if(h>500){
h=h+60;
}
//$this.controlHeight=h-99;
$this.controlHeight=h-95;
//console.log(h,$this.controlHeight,'$this.controlHeight');
})
//console.log('this.contentData11:',this.contentData,this.curriculumData)
// 视频设置禁用处理逻辑,如果用户已全部观看完该视频则设置为能全部拖动的逻辑把isDrag设置为true即可,同时删除本地存储的数据
if(this.contentData.progressVideo ===1){
var obj = JSON.parse(this.contentData.content)
obj.isDrag = true
this.contentData.content = JSON.stringify(obj)
this.curriculumData.isDrag = true
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
//alert(con.progressVideo+'--'+con.id + '--'+JSON.stringify(arr))
delete arr[this.contentData.id];
localStorage.setItem('videoProgressData',JSON.stringify(arr))
}
if(this.contentData.progressVideo>0 && this.contentData.progressVideo !==1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
arr[this.contentData.id] = this.contentData.progressVideo
localStorage.setItem('videoProgressData',JSON.stringify(arr))
}
},
isShowTime(){
if(this.isContentTypeTwo != this.contentData.contentType){
return
}
this.contentData.status = 2;
},
showRes(r, i, index,item) { //i:子节下标index:章下标
// 无权限查看不能点击
if(!this.isCrowd){
return
}
if (i != undefined && i!=-1 && 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.changePlayRes(r,item);
},
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;
let event = {
key: "ScoreCourse", //后台的事件key 发布文章且审核通过
title: "完成课程评分", //事件的标题
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
}
this.$store.dispatch("userTrigger", event);
} else {
this.$message.error('打分处理失败,请稍后再试');
}
});
}
},
praiseContent() {
if(this.isTrample) {
this.$message.error('您已踩过了,不能再赞了');
return;
}
if(this.interactRuning) {
return;
}
this.interactRuning = true;
let teacherId='';
if(this.teachers.length>0){
teacherId=this.teachers[0].teacherId;
}else{
teacherId=this.courseInfo.sysCreateAid
}
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--;
let event = {
key: "CancelPraise",//点赞
title: "取消点赞",//事件的标题
parameters:"author:"+teacherId,//用户自定义参数 name:value,name:value
content: "取消点赞课程",//事件的内容
objId: this.courseId,//关联的id
objType: "1",//关联的类型
objInfo: this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name,//当前人的姓名
status: 1 //状态直接写1
}
this.$store.dispatch("userTrigger", event);
} 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++;
let event = {
key: "Praise",//点赞
title: "点赞",//事件的标题
parameters:"author:"+teacherId,//用户自定义参数 name:value,name:value
content: "点赞了课程",//事件的内容
objId: this.courseId,//关联的id
objType: "1",//关联的类型
objInfo: this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name,//当前人的姓名
status: 1 //状态直接写1
}
this.$store.dispatch("userTrigger", event);
//发送点赞消息
let firstTeacher=this.teachers[0];
let message={
content:this.userInfo.name+'点赞了我的课程-'+this.courseInfo.name,
refId:this.courseInfo.id,
refType:1,
source:1,
pageType:1,
pageParams:this.courseInfo.id,
pageUrl:location.href,
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.$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;
if(author.avatar){
item.avatar=this.fileBaseUrl + author.avatar;
}
return true;
} else {
return false;
}
});
});
} else {
//console.log('加载课程信息失败:'+res.error);
//this.$message.error(res.message);
}
});
},
onPlayerPlay() {
//console.log("开始播放");
// if(this.contentData.contentType == 10){
// if(this.contentData.status<2){
// this.contentData.status = 2;
// }
// }
this.playerBoxShow = false;
// this.onPlayerPlayFullscreen()
// this.$watermark.set(this.userInfo.name + this.userInfo.loginName);
let $this = this;
//这里有些不准备,如果文件未能加载,这个事件就是错误的
this.isAppendTime=true;
this.appendStudyTime();//启动追加学习时长
//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();
// }
// }
},
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 {
console.log("去除水印 ---- gx ----");
var markDiv = div.querySelector("#" + divId);
console.log("去除水印 ---- gx markDiv ----",markDiv);
if (markDiv) {
console.log("执行去除水印 ---- gx markDiv ----",markDiv);
div.removeChild(markDiv);
}
}
},
onPlayerPause() {
//console.log("暂停");
this.stopStudyTime();
},
onPlayerEnded() {
this.playerBoxShow = true;
this.stopStudyTime();
if(this.contentData.status < 9) {
this.finishStudyItem();
}
},
onPlayerPlaying(itme) {
this.isAppendTime = true;//可以追加学习时长
this.intTimeNote = parseInt(itme);
//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('this.courseInfo:',this.contentData)
if(!this.curriculumData.isDrag && this.contentData.progressVideo !=1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
if(arr[this.blobId] && this.contentData.progressVideo<arr[this.blobId]) {
postData.progressVideo = arr[this.blobId]
postData.contentId = this.contentData.id
postData.courseId = this.contentData.courseId
}
}
//console.log('记录播放时间')
apiStudy.studyVideoTime(postData).then(rs => {
if (rs.status != 200) {
console.log('记录播放时间错误');
}
});
}
}
},
audioPlaying(item, currentTime) {
//console.log("当前播放"+item);
let intTime = parseInt(currentTime);
this.handleAudioTimeUpdate(intTime)
//判断是否完成
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('this.courseInfo:',this.contentData)
if(!this.curriculumData.isDrag && this.contentData.progressVideo !=1){
var time = localStorage.getItem('videoProgressData')
var arr = time&&JSON.parse(time) || {}
if(arr[this.blobId] && this.contentData.progressVideo<arr[this.blobId]) {
postData.progressVideo = arr[this.blobId]
postData.contentId = this.contentData.id
postData.courseId = this.contentData.courseId
}
}
//console.log('记录播放时间')
apiStudy.studyVideoTime(postData).then(rs => {
if (rs.status != 200) {
console.log('记录播放时间错误');
}
});
}
},
audioPlay() {
//console.log("开始播放");
// if(this.contentData.contentType == 20 && this.contentData.status < 2){
// this.contentData.status = 2;
// }
let $this = this;
this.isAppendTime=true;
this.appendStudyTime();//启动追加学习时长
},
audioPause() {
//console.log("暂停");
this.stopStudyTime();//停止追加学习时长
},
audioEnd() {
//console.log("播放结束");
this.stopStudyTime();//启动追加学习时长
if (this.contentData.status < 9) {
this.finishStudyItem();
}
},
// 获取数据信息
loadData() {
let $this=this;
apiStudy.studyIndexPost({
cid: this.courseId,
addView:true,
audiences:this.audiences
}).then(rs => {
if (rs.status == 200) {
if(rs.result.contents.length==0){
$this.$message.error('课程内容已删除或课程已不再使用');
return;
}
if(!rs.result.course.enabled){
$this.$message.error('十分抱歉,此课程已停用,如需使用,请联系管理员。');
return;
}
//设置必须的字段
if(rs.result.contents.length==1){
$this.tab=2;
//console.log('内容只有一个');
}
if(!rs.result.isCrowd){
$this.$message.error('您没有查看该课程的权限');
}
// 是否播放
this.isCrowd = rs.result.isCrowd
if (rs.result.course.type == 20) { //有目录课程
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;
}else if(rs.result.course.type==10){ //无目录课程
//如果是多个的话,就需要过滤一下
let indexNum=0;
let delIndexs=[];
rs.result.contents.forEach((c,cidx) => {
c.status = 0; //
c.studyItemId = '';
c.lastStudyTime = 0;
if(c.sortIndex==1){
c.contentName=rs.result.course.name;
indexNum++;
if(indexNum>1){
delIndexs.push(cidx);
}
}else if(c.sortIndex==2){
c.contentName='作业';
}else if(c.sortIndex==3){
c.contentName='考试';
}else if(c.sortIndex==4){
c.contentName='评估';
}
});
if(delIndexs.length>0){
delIndexs.forEach(delIdx=>{
rs.result.contents.splice(delIdx,1);
})
}
}
this.courseInfo = rs.result.course;
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,
sign:''
};
userIds.push(item.teacherId);
ctoUsers.push({
aid: item.teacherId,
name: item.teacherName
});
});
this.toUsers = ctoUsers;
this.loadAuthorInfo(rs.result.teachers, userIds);
this.teachers = rs.result.teachers;
}
this.contentList = rs.result.contents;
//处理内容的名称
this.totalContent = rs.result.contents.length;
//加载学习的数据
//this.loadStudyData();
this.loadStudyData(rs.result);
} else {
this.$message.error(rs.message);
}
});
},
loadStudyData(result) {
let $this=this;
this.loadScorePraiseAndTrample();
this.studyId = result.studyId;
//对已学习的内容进行比对,重要的字段, 学习内容id在后缀的
let playIndex = -1;
this.contentList.forEach((con, conIdx) => {
result.contentStudys.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;
con.progressVideo = scon.progressVideo;
//以下判断是为了兼容之前的问题,学习状态
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 (this.courseInfo.type == 10) {
///console.log(this.contentList[0],'ccccc11111')
this.showRes(this.contentList[0]);
} else {
//如果没有,就定位第一项内容
if (playIndex === -1) {
// this.showRes(this.contentList[0]);
//console.log(this.catalogTree,'ccccc22222')
this.showRes(this.catalogTree[0].children[0])
} else {
//console.log(this.contentList[0],'ccccc3333')
this.showRes(this.contentList[playIndex]);
}
}
},
saveScormStudy() {
//只记录SCORM课件的学习
if (this.contentData.contentType != 50) {
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: 1,
status: 2,
contentTotal: this.totalContent
};
apiStudy.studyContent(params).then(res => {
if (res.status == 200) {
this.contentData.status = 2; //进行中
this.contentData.studyItemId = res.result; //学习记录id
} else {
console.log('记录学习失败:' + res.message + '' + res.error);
}
});
},
saveStudyInfo() {
this.tentative = true
if(this.isContentType){
if(this.isContentType != this.contentData.contentType){
//定时器产生的,不记录
return
}
}
//记录课件学习信息
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);
}
});
},
homeWorkSubmit(){
if(this.contentData.contentType == 60){
this.contentData.status = 9;
}
},
startTest(val){
if(this.contentData.contentType == 61){
if(this.contentData.status < 2){
this.contentData.status = 2;
}
}
},
progress(val) {
const progressValue = parseFloat(val) * 100;
this.sendEventProgress = Number(progressValue.toFixed(2));
},
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":"page",
"objInfo": ""+this.courseInfo.name,
"aid":this.userInfo.aid, //当前登录人的id
"aname":this.userInfo.name,//当前人的姓名
"status": 1, //状态
"contentId": this.contentData.id,
}
if(this.resType == 10){
postData.progress = this.sendEventProgress;
}
//静默处理
apiStat.sendEvent(postData).then(rs=>{
if(rs.status == 200) {
// this.appendStartTime = new Date();//重新计时
// studyUtil.clearStudyDuration(); //清除本地存储
} else {
console.log(rs.message);
}
});
let postAppendData = {
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(postAppendData).then(rs => {
if (rs.status == 200) {
this.appentId = rs.result;
studyUtil.clearStudyDuration(); //清除本地存储
} else {
console.log(rs.message);
}
});
}
},
//结束追加学习时长
stopStudyTime(){
//console.log('停止追加学习时长');
this.isAppendTime=false;
//暂停让他为空 从新计时
this.appendStartTime = null
if (this.appendHandle != null) {
window.clearTimeout(this.appendHandle);
}
},
appendStudyTime() {
// 暂停的时候重新从十五秒开始计时
if(!this.appendStartTime){
this.appentInterval = 15
}
//重新覆盖时间
this.appendStartTime = new Date().getTime();
//console.log('开始追加学习时长',this.isAppendTime);
if (this.studyId == '') {
return;
}
if (!this.contentData.id) {
return;
}
if (!this.isAppendTime) {
return;
}
this.appendHandle && window.clearTimeout(this.appendHandle);
//启动下次追加学习时长
this.appendHandle = setTimeout(() => {
let endTime = new Date().getTime();
this.appentInterval = 60
let totalTime = Math.round((endTime - this.appendStartTime) / 1000);
this.appendStudyTime();
this.saveStudyDuration(totalTime)
}, this.appentInterval * 1000);
},
//追加学习时长, flag是否提交到后台
// appendStudyTime() {
// //console.log('开始追加学习时长',this.isAppendTime);
// 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();
// //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(); //相差的毫秒数
// // console.log(m/1000,'时间');
// let sen = Math.round(m / 1000); //计算秒数
// // console.log('定时器时间',sen);
// // 每次添加的是定时器计时的时间
// 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);
// },
finishStudyItem() { //设置完成学习的内容,针对于音视频的内容
if (!this.contentData.studyItemId) {
//这种可能没有不过这里也是为了万中那个1
!this.tentative && 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);
}
});
}
},
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);
}
});
},
formatTime(duration) {
let min = 0;
if (duration > 0) {
min = parseInt(duration / 60);
}
return min;
},
heartabone() {
this.tab = 1
},
heartabtwo() {
this.tab = 2
},
handleAudioTimeUpdate(currentTime) {
// if(this.contentStudysLength.length == 0){
let params = {
studyId: this.studyId, //学习id,
courseId: this.courseId, //课程id,
contentId: this.contentData.id, //内容id,
contentType: this.contentData.contentType,
contentName: this.contentData.contentName, //内容名称
progress: 1,
status: 2,
contentTotal: this.totalContent
};
if(currentTime > 2 && this.trueFalse){
apiStudy.studyContent(params).then(()=>{
if(this.contentData.status<2){
this.contentData.status = 2;
}
})
this.trueFalse = false
}
// }
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .el-icon-arrow-down{
color: #000;
font-weight: 900;
font-size: 16px;
}
.el-menu,
.el-menu-item,
.el-submenu__title {
background-color: transparent !important; /* 设置背景色为透明,以移除默认的背景颜色变化 */
color: inherit !important; /* 确保文字颜色不变,如果需要的话 */
}
/* 取消选中效果 */
.el-menu-item.is-active,
.el-submenu__title.is-active {
background-color: transparent !important; /* 移除选中时的背景色 */
color: inherit !important; /* 保持文字颜色与未选中时一致,如果需要的话 */
}
/* 如果有特定的 hover 样式,也可以取消 */
.el-menu-item:hover,
.el-submenu__title:hover {
background-color: transparent !important; /* 移除鼠标悬停时的背景色变化 */
color: inherit !important; /* 保持文字颜色不变 */
}
//内容块样式定义
.course-content {
min-height: 745px;
margin: 20px auto;
.course-playbox {
background-color: #fff;
min-height: 400px;
display: flex;
justify-content: space-between;
.course-player{ //内容播放区域
flex:1;
min-width: 700px;
min-height: 400px;
max-height: 800px;
//height: 100%;
border: 1px solid #ffffff;
padding-right: 20px;
// overflow: auto;
}
.course-control{ //内容控制区域
width: 420px;
}
}
.course-infobox {
margin-top: 20px;
display: flex;
justify-content: space-between;
.course-info {
flex:1;
min-width: 700px;
min-height: 710px;
box-sizing: border-box;
padding-right: 20px;
}
.course-teacher{
width: 420px;
}
}
}
.control-tab {
margin: 35px 30px 10px 30px;
border-bottom: 1px solid #D8D8D8;
display: flex;
justify-content: space-around;
padding-bottom: 12px;
div {
color: #666666;
cursor: pointer;
}
.control-tab-active {
color: #333333;
font-weight: 600;
}
}
.course-info-tab {
display: flex;
padding-top: 30px;
margin-left: 47px;
div {
color: #333333;
font-size: 16px;
cursor: pointer;
margin-right: 50px;
}
.course-info-tab-active {
color: #333333;
font-weight: 600;
position: relative;
span {
display: inline-block;
width: 69px;
height: 4px;
background: #387DF7;
border-radius: 5px;
position: absolute;
left: 0;
top: 128%;
}
}
}
.course-info-row{
padding: 10px 0;
font-size: 18px;
color: #343434;
img{
width:18px
}
.course-info-text{
margin: 10px 0;
font-size: 14px;
text-indent: 2em;
color: #666666;
word-break: break-all;
}
}
//右侧老师部分头部及标题
.cteacher-top {
background-color: #fff;
margin-top: 0px;
.cteacher-top-bar{
width: 100%;
height: 15px;
}
.cteacher-top-title{
padding-left:30px;
padding-top:10px;
font-size: 16px;
font-weight: 600;
line-height: 50px;
}
}
//右侧老师部分 老师列表
.cteacher-list {
background-color: #fff;
padding: 10px 30px 30px 30px;
}
//以下是未整理的样式,上面的整理之后的样式
.coures-note {
min-height: 500px;
padding-left: 17px;
padding-top: 10px;
.note-tole {
color: #333333;
font-size: 18px;
font-weight: 600;
}
.note-info {}
}
.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-text {
font-size: 18px;
color: #ffb30f;
font-family: 'Arial';
margin-left: 23px;
// font-weight: 600;
}
// .score {
// display: flex;
// justify-content: center;
// align-items: center;
// .el-rate {
// display: inline-block;
// }
// // 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: 16px;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
.con-audio {
padding: 50px;
text-align: center;
.con-audio-title {
font-size: 16px;
font-weight: 700;
}
.con-audio-player {
min-height: 300px;
padding: 60px 50px 80px 50px;
}
}
.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: 100%;
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);
}
}
}
}
::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;
width: 100%;
border-top: none;
padding: 10px 0px;
.teacher-avator {
cursor: pointer;
::v-deep .el-avatar {
width: 60px !important;
height: 60px !important;
border-radius: 50%;
img{
width: 100% !important;
}
}
.teacher-text {
width: 68px;
height: 68px;
div {
img {
width: 68px;
height: 68px;
}
}
}
}
.teacher-info {
flex: 1;
.teacher-name {
padding: 5px 5px 10px 10px;
}
.teacher-remark {
padding: 0px 5px 0 10px;
font-size: 14px;
color: #666666;
line-height: 20px;
overflow:hidden;
text-overflow:ellipsis;
// white-space:nowrap;
word-break:break-all
}
}
}
.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
}
}
}
.course-units {
padding: 10px 30px;
.units-info {
padding: 0 30px;
height: 60px;
line-height: 60px;
font-size: 16px;
cursor: pointer;
overflow: hidden;
white-space:nowrap;
word-break:break-all;
text-overflow:ellipsis;
}
.units-active {
background: #F6F6F6;
color: #387DF7;
font-weight: 600;
cursor: text;
img {
width: 18px;
height: 20px;
vertical-align: middle;
// margin-right: 20px;
}
}
}
.more {
float: right;
}
.coures-title {
margin-left: 82px;
font-size: 20px;
font-weight: 600;
color: #FFFFFF;
margin-top: 25px;
div {
float: left;
font-size: 20px;
font-weight: 600;
color: #FFFFFF;
line-height: 20px;
}
span {
float: left;
font-size: 16px;
font-weight: 400;
color: #FFFFFF;
margin-left: 27px;
}
h6 {
float: left;
font-size: 16px;
font-weight: 600;
color: #FFFFFF;
margin: 0 20px;
}
}
::v-deep.el-breadcrumb__item:first-child .el-breadcrumb__inner a,
.el-breadcrumb__inner .is-link {
color: #fff !important;
}
::v-deep.el-breadcrumb__item:last-child .el-breadcrumb__inner {
color: #fff !important;
}
::v-deep.hear-nav {
color: #fff !important;
}
.breadcrumb-nav {
color: #FFFFFF;
}
.coures-bg {
width: 100%;
height: 200px;
background: url('../../../public/images/couresdetail.png');
}
</style>