<template>
<view>
<view class="new-tab">
<img class="new-tab-img-back" :src="backImgUrl" alt="" @click="comeBack">
</view>
<u-loading-icon v-if='loading' text="加载中" textSize="18"></u-loading-icon>
<view v-else>
<!-- 0=文档1=视频 -->
<view v-if="data.type==1">
<view class="content">
<view class="landscape-container" :class="{'text-area-max':type}">
<view class="text-area">
<video id="myVideo" class="video-class" @error="videoErrorCallback" controls
:autoplay='true' enable-progress-gesture='false' @play="playVideo" @ended="videoEnd"
@pause="videoPause" :src="Url" @waiting='waitVideo' :direction='90' :initial-time='data.learnTime'
@timeupdate="watchTimeVideo" show-fullscreen-btn='false'>
</video>
<cover-view class="controls">
<cover-image v-if="type" class="controls-btn" src="@/static/hy.png" @click="check()">
</cover-image>
<cover-image v-else class="controls-btn" src="@/static/qp.png" @click="check()">
</cover-image>
</cover-view>
<cover-view class="other-view" v-if="name == '培训'" @click="clickCountDown">
{{countdowns}}秒
</cover-view>
</view>
</view>
</view>
<view class="text_content">
{{data.name || '-'}} {{data.describe || '-'}}
</view>
<view class="text_content">
课件所需学习时长:{{data.schoolTime ||' -'}}分钟
</view>
<view class="text_content">
观看人次:{{data.watchCount}}
</view>
</view>
<!-- 文档 -->
<view v-else>
<view class="padding10">课件所需学习时长:{{data.schoolTime ||' -'}}分钟 ({{data.schoolTimeSeconds}}秒)</view>
<view class="padding10">已学习:{{documentLearnTime ||' -'}}秒</view>
<view v-for="(item,index) in pictureList">
<img :src="item" alt="" class="fileImg">
</view>
</view>
</view>
</view>
</template>
<script>
import {
EducationCourseware,
EducationExitCourseware
} from '@/common/login.js'
import api from '@/main.js'
import '@/components/shoyu-xxtea/shoyu-xxtea'
import {
throttle
} from "@/util"
export default {
data() {
return {
backImgUrl: require('@/static/back.png'),
type: false,
danmuValue: '',
btn: 0,
testTime: null,
loading: true,
schoolTime: 0,
sumTime: 0,
id: '',
timestamp: 10,
data: {
type: 0
},
Url: '',
u2: '',
fileUrl: '',
biz: '', //所属模块(课件中心=center,岗位必学=postLearn,我的培训=training)
name: '',
ti: 1,
timer: 0,
hour: 0,
minutes: 0,
seconds: 0,
coursewareId: '',
limitTime: '',
remindCycle: 8,
countdown: 8,
urlPath: '',
title: '',
viewerUrl: '/hybrid/html/web/viewer.html',
allUrl: '',
downloadFile_onoff: false,
reachButtom: 0, //代表是不是触底--用来判断文档
pictureList: [],
isPause: 0, //是否倒计时结束
videoContext: '', //储存视频对象
isOver: 0, //是否播放结束过--判断时长累加
ti: 0, //实时播放进度
nitial_time: '', //视频跳转进度 秒
documentLearnTime: '', //文档学习时间
countdowns: 0,
timerCountDown: '', //倒计时实例
numCycleTime:1, //节流时间
playOrPause:0,//播放为0 暂停为1
}
},
onLoad(e) {
this.id = e.id || ''
this.coursewareId = e.coursewareId || ''
this.name = e.name
this.value = e.value
console.log("看课件title/value", this.name, this.value);
if (this.name == '我的学习' || this.value == '课件中心') {
this.biz = 'center'
} else if (this.name == '培训') {
this.biz = 'training'
} else {
//岗位必学
this.biz = 'postLearn'
}
console.log("this.biz", this.biz);
this.getData({})
this.initial_time = '0' //视频进度
/* 隐藏顶部状态栏 */
// #ifndef MP-ALIPAY
plus.navigator.setFullscreen(true);
this.videoContext = uni.createVideoContext('myVideo')
// #endif
const that = this
const landscapeOb = uni.createMediaQueryObserver(this)
landscapeOb.observe({
orientation: 'landscape' //屏幕方向为纵向/横向 portrait/landscape
}, matches => {
console.log(matches);
that.type = matches
this.landscape = matches
})
},
methods: {
showBtn(e) {
this.btn = !this.btn
},
check() {
const asd = this.type ? 'portrait' : 'landscape'
plus.screen.lockOrientation(asd);
},
sendDanmu: function() {
this.videoContext.sendDanmu({
text: this.danmuValue,
color: this.getRandomColor()
});
this.danmuValue = '';
},
getRandomColor: function() {
const rgb = []
for (let i = 0; i < 3; ++i) {
let color = Math.floor(Math.random() * 256).toString(16)
color = color.length == 1 ? '0' + color : color
rgb.push(color)
}
return '#' + rgb.join('')
},
// 获取日常任务
async getData(params) {
let id = ''
if (this.name == '我的学习') {
id = this.coursewareId
} else {
id = this.id
}
const data = {
id: id,
biz: this.biz
}
console.log(data);
const res = await EducationCourseware(data)
if (res.code == 200) {
console.log("res", res);
this.data = res.result;
// this.data.learnTime = 3
this.schoolTime = (this.data.coursewareFile.schoolTime * 1 / 60).toFixed(2) //课件学习时长 分钟
this.limitTime = this.data.videoTime * 1 //视频总秒数
this.remindCycle = this.data.remindCycle * 1 * 60 //提醒周期 秒
this.countdown = this.data.countdown * 1 //弹窗时间
this.countdowns = this.data.countdown * 1 //页面显示的倒计时
this.numCycleTime = this.remindCycle + this.countdown //节流时间
console.log("这些时间", this.remindCycle, this.countdowns, this.numCycleTime);
this.Url = getApp().globalData.urlApiFile + res.result.coursewareFile.filePath
console.log("视频真正地址",this.Url);
//文档
if (this.data.type == 0) {
this.documentLearnTime = this.data.learnTime || 0 //接口返回上次看到的时间--赋值
var filePngPath = res.result.coursewareFile.filePngPath.split(',');
var newList = []
for (var i = 0; i < filePngPath.length; i++) {
newList.push(getApp().globalData.urlApiFile + filePngPath[i])
}
this.pictureList = newList
setInterval(() => {
this.timer += 1
this.documentLearnTime += 1
}, 1000);
console.log('newList', newList)
}
this.loading = false
}
},
//开始
startTimer() {},
//暂停
videoPause(e) {
// console.log("暂停", e);
this.playOrPause = 1
clearInterval(this.timer);
clearInterval(this.timerCountDown)
// console.log("时间", this.ti);
},
//视频播放缓冲
waitVideo() {
clearInterval(this.timer); //暂停计时
// this.$refs.countDown.pause() //倒计时暂停
},
watchTimeVideo(e) {
let that = this;
// videoContext.seek(that.data.learnTime);
let videoContext = wx.createVideoContext('myVideo');
if (this.name == '培训') {
if (that.data.learnTime * 1 !== 0) {
videoContext.seek(that.data.learnTime);
that.data.learnTime = 0
return
}
var isReady = 1; // 是否开启可以视频快进 1 禁止开启
//跳转到指定播放位置 initial-time 时间为秒
//播放的总时长
var duration = e.detail.duration;
//实时播放进度 秒数
var currentTime = parseInt(e.detail.currentTime);
console.log("视频播放到第" + currentTime + "秒") //查看正在播放时间,以秒为单位
if (that.ti == 0) {
var jump_time = parseInt(that.initial_time) + parseInt(that.ti);
} else {
var jump_time = parseInt(that.ti);
}
console.log("that.data.learnTime", that.data.learnTime);
if (isReady == 1) {
if (currentTime > jump_time && currentTime - jump_time > 3) {
uni.showToast({
title: '视频不支持快进' + that.ti,
icon: 'none',
});
videoContext.seek(that.ti);
}
}
}
that.ti = currentTime; //实时播放进度
},
playVideo(e) {
console.log("播放1", e, this.ti);
this.playOrPause = 0
//开始计时
this.timer = setInterval(this.startTimer, 1000);
// const that = this
if (this.name == '培训') {
if (this.limitTime - this.ti > this.remindCycle) {
console.log("fhr");
this.countdowns = this.data.countdown * 1
this.watchTime()
}
}
},
//防作弊
watchTime() {
const that = this
console.log('防作弊');
if (that.name == '培训') {
that.test(that, that.numCycleTime)
}
},
test: throttle((that, numCycleTime) => {
setTimeout(function() {
console.log("89898989", numCycleTime);
that.timerCountDown = setInterval(() => {
if (that.countdowns <= 0) {
//倒计时到0的时候 暂停视频 倒计时重新赋值
that.videoContext = uni.createVideoContext('myVideo');
that.videoContext.pause(); //暂停
clearInterval(that.timerCountDown)
} else {
that.countdowns--
}
}, 1000)
}, that.remindCycle * 1000);
}, 3000),
//倒计时点击事件
clickCountDown() {
console.log("用户点击按钮");
const that = this
clearInterval(that.timerCountDown)
that.countdowns = that.data.countdown * 1
that.videoContext = uni.createVideoContext('myVideo'); //创建视频实例指向video
//如果已经暂停了,调用播放 未暂停调用周期防作弊
if(this.playOrPause == 1){
console.log("已经暂停了");
that.videoContext.play(); //播放
}else{
console.log("防止暂停");
if (that.limitTime - that.ti > that.remindCycle) {
console.log("fhr");
that.countdowns = that.data.countdown * 1
that.watchTime()
}
}
},
//视频播放出错
videoErrorCallback(e) {
clearInterval(this.timer);
clearInterval(that.timerCountDown)
console.log("出错", e);
},
//视频播放完结束
videoEnd(e) {
// console.log("播放完了,当前时间/总时长", this.ti,this.limitTime);
this.sumTime = this.ti + this.sumTime
console.log("ti/sumTime",this.ti,this.sumTime);
clearInterval(this.sumTime);
clearInterval(this.timer);
clearInterval(this.timerCountDown)
// this.ti = 0
this.isOver = 1
},
//左上角返回
comeBack() {
clearInterval(this.timer); //计时器停止
console.log("左上角要调用接口", this.timer, this.ti);
let id = ''
let ti = ''
if (this.name == '我的学习') {
id = this.coursewareId
} else {
id = this.id
}
if (this.data.type == 0) {
ti = this.timer // 文档
} else {
// //判断用累加时长还是当前时长
// if (this.isOver == 1) {
// ti = this.sumTime
// }
ti = this.ti //视频
}
let form = {
id: id,
biz: this.biz,
time: ti,
coursewareId: '',
isBottom: this.reachButtom
}
console.log('提交的数据', form);
const res = EducationExitCourseware(Object.assign({
id: id,
biz: this.biz,
time: ti,
coursewareId: '',
isBottom: this.reachButtom
}))
console.log("左上角调用接口完毕", res);
clearInterval(this.timerCountDown)
uni.navigateBack(-1)
},
//返回触发
onBackPress(options) {
console.log("options", options.from);
//避免死循环
if (options.from === 'navigateBack') return false;
//自己的判断条件,执行自定义的返回操作
if (options.from !== 'navigateBack') {
clearInterval(this.timer); //计时器停止
console.log("返回前要调用接口", this.timer, this.ti);
let id = ''
let ti = ''
if (this.name == '我的学习') {
id = this.coursewareId
} else {
id = this.id
}
if (this.data.type == 0) {
ti = this.timer // 文档
} else {
//判断用累加时长还是当前时长
if (this.isOver == 1) {
ti = this.sumTime
}
ti = this.ti //视频
}
let form = {
id: id,
biz: this.biz,
time: ti,
coursewareId: '',
isBottom: this.reachButtom
}
console.log('提交的数据', form);
const res = EducationExitCourseware(Object.assign({
id: id,
biz: this.biz,
time: ti,
coursewareId: '',
isBottom: this.reachButtom
}))
clearInterval(this.timerCountDown)
console.log("接口调用完毕允许返回", res);
uni.navigateBack(-1)
}
//返回true表示我要自定义onBackPress
return true
},
//触底-用于文档验证
onReachBottom() {
this.reachButtom = 1
},
},
}
</script>
<style>
page {
background-color: #EFF1F5;
}
.new-tab {
width: 100%;
height: 100px;
background-color: #556585;
}
.new-tab-img-back {
width: 25px;
height: 25px;
margin-top: 60px;
margin-left: 20px;
}
.text_content {
padding: 30upx;
color: #333333;
font-size: 30upx;
}
.shijian {
font-size: 16px;
text-align: center;
color: white;
z-index: 999999;
}
.count-down {
width: 80px;
height: 30px;
color: white !important;
background-color: steelblue;
text-align: center;
line-height: 30px !important;
position: absolute;
z-index: 999999;
right: 0;
}
.count-down-son {
width: 80px;
height: 30px;
z-index: 9999999;
}
.padding10 {
padding: 10px;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.landscape-container {
height: 300px;
}
.text-area {
position: relative;
width: 100vw;
height: 100%;
display: flex;
justify-content: center;
}
.text-area-max {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #000;
display: flex;
align-items: center;
}
.video-class {
width: 100%;
height: 100%;
}
.other-view {
position: absolute;
color: white;
font-size: 16px;
text-align: center;
top: 0;
right: 0;
width: 100px;
height: 30px;
background-color: #556585;
}
.controls {
position: absolute;
bottom: 2%;
right: 2%;
/* background: #ff; */
color: #000;
text-align: center;
}
.controls-btn {
width: 15px;
height: 15px;
padding: 10px;
}
.bottom-list {
border: 1px solid;
}
</style>
<style lang="scss" scoped>
.u-tabs {
background-color: #ffffff;
}
.fileImg {
width: 750upx;
height: 1440upx;
}
.task-list {
.content {
color: #00000073;
}
.left {
margin-left: 40rpx;
}
.green {
color: #45CEA1;
}
.red {
color: #FF5F56;
}
}
.u-input {
width: 400rpx;
}
</style>
节流重点代码:
export const throttle =(fn, wait = 3000) => {
let flag = true
return function () {
if (!flag) return
flag = false
fn.apply(this, arguments)
setTimeout(() => {
flag = true
}, wait)
}
}
效果图:(顶部导航栏自己写的,屏蔽了原生的,不然视频全屏会受影响)