|
@@ -5,7 +5,14 @@
|
|
|
backgroundImage: `url(${$tools.splitImgHost(goodsData.coverUrl, false)})`
|
|
|
}"
|
|
|
>
|
|
|
-
|
|
|
+ <div id="player"></div>
|
|
|
+ <div class="recordStyle" v-if="showRecordStatus">
|
|
|
+ 您上次看{{
|
|
|
+ $tools.secondToTime(this.activeSection.videoCurrentTime)
|
|
|
+ }},正在自动续播
|
|
|
+ <span class="videoCurrentTime_style">|</span>
|
|
|
+ <span class="btn_sty" @click="seekVideo0">从头播放</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -13,7 +20,16 @@
|
|
|
export default {
|
|
|
inject: ["getGoodsData"],
|
|
|
data() {
|
|
|
- return {};
|
|
|
+ return {
|
|
|
+ vodPlayerJs: "https://player.polyv.net/script/player.js",
|
|
|
+ activeSection: {},
|
|
|
+ player: null,
|
|
|
+ photoList: [], //抓拍时间拍照数组
|
|
|
+ photoHistoryList: [], //历史和已拍照数据
|
|
|
+ photoIndex: 0, //当前拍照对应索引
|
|
|
+ showRecordStatus: false, //是否显示从头播放提示
|
|
|
+ showRecordSetTimeOut: null //从头播放提示计时器函数
|
|
|
+ };
|
|
|
},
|
|
|
computed: {
|
|
|
goodsData() {
|
|
@@ -28,8 +44,400 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ created() {
|
|
|
+ if (!window.polyvPlayer) {
|
|
|
+ const myScript = document.createElement("script");
|
|
|
+ myScript.setAttribute("src", this.vodPlayerJs);
|
|
|
+ myScript.onload = () => {
|
|
|
+ console.log("加载成功");
|
|
|
+ };
|
|
|
+ document.body.appendChild(myScript);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.$bus.$on("toPlay", async item => {
|
|
|
+ this.activeSection = Object.assign({}, item);
|
|
|
+ if (this.player) {
|
|
|
+ this.player.destroy(); //初始化播放器
|
|
|
+ }
|
|
|
+ await this.getRecordLast(); //获取播放记录
|
|
|
+ await this.getRecordHistoryPhoto(); //获取拍照历史记录
|
|
|
+ await this.loadPlayer(); //加载播放内容
|
|
|
+ this.player.on("s2j_onPlayerInitOver", () => {
|
|
|
+ this.player.HTML5.video.addEventListener("timeupdate", this.timeEvent); //监听器
|
|
|
+ this.player.on("s2j_onPlayStart", this.onPlayStatus); //视频初次播放时触发
|
|
|
+ this.player.on("s2j_onVideoPause", this.onVideoPause); //视频暂停时触发
|
|
|
+ this.player.on("s2j_onPlayOver", this.onPlayOver); //当前视频播放完毕时触发
|
|
|
+ this.player.on("s2j_onPlayerError", this.onPlayerError); //播放出现错误时触发
|
|
|
+ this.player.on("serverError", this.serverError); //发生业务逻辑错误时触发,比如授权验证失败、域名黑白名单验证不通过等错误。参数返回事件名称和错误代码。
|
|
|
+ }); //播放器初始化完毕时触发。播放器提供的方法需要在此事件发生后才可以调用。
|
|
|
+ });
|
|
|
+ },
|
|
|
methods: {
|
|
|
- getBeforeWork() {}
|
|
|
+ getBeforeWork() {},
|
|
|
+ //获取播放记录
|
|
|
+ getRecordLast() {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ clearTimeout(this.showRecordSetTimeOut);
|
|
|
+ let data = {
|
|
|
+ // orderGoodsId: this.goodsData.orderGoodsId,
|
|
|
+ gradeId: this.goodsData.gradeId,
|
|
|
+ goodsId: this.goodsData.goodsId,
|
|
|
+ courseId: this.activeSection.courseId,
|
|
|
+ moduleId: this.activeSection.moduleId,
|
|
|
+ chapterId: this.activeSection.chapterId,
|
|
|
+ sectionId: this.activeSection.sectionId
|
|
|
+ };
|
|
|
+ this.$request.recordLast(data).then(res => {
|
|
|
+ if (res.data && res.data.videoCurrentTime) {
|
|
|
+ this.activeSection.videoCurrentTime = res.data.videoCurrentTime;
|
|
|
+ }
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //从头播放
|
|
|
+ seekVideo0() {
|
|
|
+ this.player.j2s_seekVideo(0);
|
|
|
+ this.showRecordStatus = false;
|
|
|
+ },
|
|
|
+ //获取拍照历史记录
|
|
|
+ getRecordHistoryPhoto() {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ var data = {
|
|
|
+ sectionId: this.activeSection.sectionId,
|
|
|
+ goodsId: this.goodsData.goodsId,
|
|
|
+ courseId: this.activeSection.sectionId,
|
|
|
+ gradeId: this.goodsData.gradeId,
|
|
|
+ chapterId: this.activeSection.chapterId,
|
|
|
+ moduleId: this.activeSection.moduleId
|
|
|
+ };
|
|
|
+ this.$request.getPhotoLastRecord(data).then(res => {
|
|
|
+ //清空历史数据
|
|
|
+ this.photoList = [];
|
|
|
+ this.photoHistoryList = [];
|
|
|
+ this.photoIndex = 0;
|
|
|
+ for (let i = 0; i < res.data.length; i++) {
|
|
|
+ //-2存储随机拍照数组
|
|
|
+ if (res.data[i].photoIndex == -2 && res.data[i].timeInterval) {
|
|
|
+ this.photoList = res.data[i].timeInterval.split(",");
|
|
|
+ } else {
|
|
|
+ this.photoHistoryList.push(res.data[i].photoIndex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //计算拍照逻辑
|
|
|
+ photoLogic() {
|
|
|
+ if (this.photoList.length > 0 || this.activeSection.learning == 1) return; //已从历史拍照数据获得
|
|
|
+ var polyvPlayerContext = this.player;
|
|
|
+ let totalVideoTime = polyvPlayerContext.j2s_getDuration();
|
|
|
+ let duration = polyvPlayerContext.j2s_getCurrentTime();
|
|
|
+ if (this.goodsData.erJianErZao) {
|
|
|
+ this.photoList = this.randomConfig(totalVideoTime, duration);
|
|
|
+ } else if (this.goodsData.jjShiGongYuan) {
|
|
|
+ this.photoList = this.ShiPhotoList(totalVideoTime, duration);
|
|
|
+ } else if (this.goodsData.goodsPhotographConfig.photoNum > 0) {
|
|
|
+ this.photoList = this.getPhotoList(
|
|
|
+ totalVideoTime,
|
|
|
+ this.goodsData.goodsPhotographConfig.photoNum
|
|
|
+ );
|
|
|
+ }
|
|
|
+ //兼容已有观看历史
|
|
|
+ for (let i = 0; i < this.photoList.length - 1; i++) {
|
|
|
+ if (this.photoList[i] < duration && this.photoList[i + 1] > duration) {
|
|
|
+ this.photoIndex = i + 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (duration > this.photoList[this.photoList.length - 1]) {
|
|
|
+ this.photoIndex = this.photoList.length - 1; //取最后一个下标
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //普通拍照
|
|
|
+ getPhotoList(totalVideoTime, photoNum) {
|
|
|
+ let photoList = [];
|
|
|
+ if (totalVideoTime >= 900) {
|
|
|
+ //大于15分钟
|
|
|
+ if (photoNum == 1) {
|
|
|
+ //开头拍1张
|
|
|
+ photoList.push(1);
|
|
|
+ } else if (photoNum == 3) {
|
|
|
+ //拍3张
|
|
|
+ photoList.push(0); //开头拍一张
|
|
|
+ let centerTime = Math.floor(totalVideoTime / 2); //获取中间时间
|
|
|
+ let centerMinTime = centerTime - 300; //前后5分钟
|
|
|
+ let centerMaxTime = centerTime + 300;
|
|
|
+ let centerTakeTime = this.randomNum(centerMinTime, centerMaxTime);
|
|
|
+ photoList.push(centerTakeTime); //中间拍一张
|
|
|
+ let endMaxTime = totalVideoTime - 60;
|
|
|
+ let endMinTime = totalVideoTime - 300;
|
|
|
+ let endTakeTime = this.randomNum(endMinTime, endMaxTime);
|
|
|
+ photoList.push(endTakeTime); //最后拍一张
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //小于15分钟,只拍前后各一张
|
|
|
+ if (photoNum == 1) {
|
|
|
+ //开头拍1张
|
|
|
+ photoList.push(1);
|
|
|
+ } else if (photoNum == 3) {
|
|
|
+ photoList.push(1);
|
|
|
+ let centerTime = this.randomNum(
|
|
|
+ (1 / 3) * totalVideoTime,
|
|
|
+ (2 / 3) * totalVideoTime
|
|
|
+ );
|
|
|
+ photoList.push(centerTime);
|
|
|
+ let endTakeTime = this.randomNum(
|
|
|
+ (2 / 3) * totalVideoTime,
|
|
|
+ totalVideoTime
|
|
|
+ );
|
|
|
+ photoList.push(endTakeTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.postCoursePhotoRecord(true); //提交随机拍照时间数组
|
|
|
+ return photoList;
|
|
|
+ },
|
|
|
+ //施工继教
|
|
|
+ ShiPhotoList(totalVideoTime) {
|
|
|
+ //施工继教带年份的订单拍照设置
|
|
|
+ let time1 = 2761; //拍照间隔多久一张 46分钟
|
|
|
+ let num = Math.trunc(totalVideoTime / time1) + 1; //拍照数量
|
|
|
+ let photoList = [];
|
|
|
+ for (let i = 0; i < num; i++) {
|
|
|
+ photoList.push(i * time1);
|
|
|
+ }
|
|
|
+ return photoList;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 随机拍摄时间(二建)
|
|
|
+ randomConfig(totalVideoTime, duration) {
|
|
|
+ this.photoHistoryList = [];
|
|
|
+ let photoList = [duration];
|
|
|
+ let pre = duration;
|
|
|
+ if (totalVideoTime > 300) {
|
|
|
+ while (pre <= totalVideoTime) {
|
|
|
+ pre += this.randomNum(780, 900);
|
|
|
+ pre <= totalVideoTime && photoList.push(pre);
|
|
|
+ }
|
|
|
+ if (totalVideoTime - 300 > photoList.slice(-1)[0]) {
|
|
|
+ photoList.push(this.randomNum(totalVideoTime - 180, totalVideoTime));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return photoList;
|
|
|
+ },
|
|
|
+ //postTime = true 只提交随机时间 false 提交拍照
|
|
|
+ postCoursePhotoRecord(postTime = false) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let currentTime = this.player.j2s_getCurrentTime();
|
|
|
+ let data = {
|
|
|
+ goodsId: this.goodsData.goodsId,
|
|
|
+ gradeId: this.goodsData.gradeId,
|
|
|
+ courseId: this.activeSection.courseId,
|
|
|
+ moduleId: this.activeSection.moduleId,
|
|
|
+ chapterId: this.activeSection.chapterId,
|
|
|
+ sectionId: this.activeSection.sectionId,
|
|
|
+ photo: this.ossAvatarUrl,
|
|
|
+ photoTime: parseInt(currentTime > 0 ? currentTime : 0),
|
|
|
+ photoIndex: postTime ? -2 : parseInt(this.photoIndex), //从0算起,-2只提交随机时间
|
|
|
+ photoNum: parseInt(this.goodsData.goodsPhotographConfig.photoNum),
|
|
|
+ timeInterval: postTime ? this.photoList.join(",") : ""
|
|
|
+ };
|
|
|
+ this.$request
|
|
|
+ .coursePhotoRecord(data)
|
|
|
+ .then(res => {
|
|
|
+ resolve();
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ reject();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //随机拍摄时间
|
|
|
+ randomNum(minNum, maxNum) {
|
|
|
+ switch (arguments.length) {
|
|
|
+ case 1:
|
|
|
+ return parseInt(Math.random() * minNum + 1, 10);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 播放视频
|
|
|
+ loadPlayer() {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ var self = this;
|
|
|
+ const polyvPlayer = window.polyvPlayer;
|
|
|
+ self.$request
|
|
|
+ .obtainpolyvvideosign(self.activeSection.recordingUrl)
|
|
|
+ .then(res => {
|
|
|
+ self.player = polyvPlayer({
|
|
|
+ wrap: "#player",
|
|
|
+ width: 810,
|
|
|
+ height: 455,
|
|
|
+ showLine: true, //是否显示线路选择按钮
|
|
|
+ ban_history_time: "on", //是否禁用续播功能,取值:{on,off}。
|
|
|
+ vid: self.activeSection.recordingUrl,
|
|
|
+ autoplay: this.goodsData.goodsPhotographConfig.autoplay, // 是否自动播放。
|
|
|
+ ban_seek: this.goodsData.goodsPhotographConfig.isAllowSeek, //是否禁止拖拽进度条,取值:{on,off}。
|
|
|
+ speed: this.goodsData.goodsPhotographConfig.playbackRate, //当speed参数值为boolean类型时,代表是否显示倍速切换的按钮。
|
|
|
+ teaser_show: 1, //是否播放片头:0 不播放,1 播放。片头可在管理后台进行设置。
|
|
|
+ tail_show: 1, //是否播放片尾:0 不播放,1 播放。片尾可在管理后台进行设置。
|
|
|
+ hideSwitchPlayer: true, //是否隐藏H5和Flash播放器的切换按钮。
|
|
|
+ watchStartTime: this.activeSection.videoCurrentTime || 0, // 播放开始时间,表示视频从第几秒开始播放,参数值需小于视频时长。
|
|
|
+ ts: res.data.ts, //移动播放加密视频需传入的时间戳。
|
|
|
+ sign: res.data.sign, //移动端播放加密视频所需的签名。
|
|
|
+ playsafe: function(vid, next) {
|
|
|
+ self.$request.obtainpolyvvideopcsign(vid).then(res => {
|
|
|
+ next(res.data);
|
|
|
+ });
|
|
|
+ } //PC端播放加密视频所需的授权凭证。
|
|
|
+ });
|
|
|
+ resolve();
|
|
|
+ return;
|
|
|
+ this.player.HTML5.video.addEventListener(
|
|
|
+ "timeupdate",
|
|
|
+ self.timeEvent
|
|
|
+ );
|
|
|
+ this.player.on("s2j_onPlayStart", () => {
|
|
|
+ //开始播放每5秒提交一次观看时间
|
|
|
+ this.hasStart = true;
|
|
|
+ clearInterval(this.postTimer);
|
|
|
+ this.postTimer = setInterval(() => {
|
|
|
+ this.postStudyRecord(0, this.playSectionId, 5);
|
|
|
+ }, 30000);
|
|
|
+ if (this.recordObj.videoCurrentTime) {
|
|
|
+ this.showRecordStatus = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.showRecordStatus = false;
|
|
|
+ }, 5000);
|
|
|
+ } else {
|
|
|
+ //新视频直接提交一条观看记录
|
|
|
+ // this.postStudyRecord(0);
|
|
|
+ this.showRecordStatus = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ this.player.on("s2j_onVideoPause", () => {
|
|
|
+ clearInterval(this.postTimer);
|
|
|
+ if (
|
|
|
+ this.sectionItem.learning != 1 &&
|
|
|
+ this.goodsData.erJianErZao
|
|
|
+ ) {
|
|
|
+ console.log(123);
|
|
|
+ this.videoPause = setTimeout(() => {
|
|
|
+ if (!this.takePhotoModal) {
|
|
|
+ if (this.isFullScreen()) {
|
|
|
+ this.exitFullscreen();
|
|
|
+ }
|
|
|
+ this.confirmStatus = true;
|
|
|
+ this.$confirm("检测暂停时间过长,刷新当前页面", "提示", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ showCancelButton: false,
|
|
|
+ closeOnClickModal: false,
|
|
|
+ closeOnPressEscape: false,
|
|
|
+ showClose: false,
|
|
|
+ type: "warning"
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.$router.go(0);
|
|
|
+ this.confirmStatus = false;
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ this.confirmStatus = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, 300000);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ this.player.on("s2j_onVideoPlay", () => {
|
|
|
+ if (this.postTimer) {
|
|
|
+ this.postTimer = setInterval(() => {
|
|
|
+ this.postStudyRecord(0, this.playSectionId, 5);
|
|
|
+ }, 30000);
|
|
|
+ }
|
|
|
+ if (this.sectionItem.learning != 1 && this.videoPause) {
|
|
|
+ clearTimeout(this.videoPause);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ this.player.on("s2j_onPlayOver", () => {
|
|
|
+ this.hasStart = false;
|
|
|
+ clearInterval(this.postTimer);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "播放完毕"
|
|
|
+ });
|
|
|
+
|
|
|
+ if (this.isFullScreen()) {
|
|
|
+ this.exitFullscreen();
|
|
|
+ }
|
|
|
+ this.postStudyRecord(1);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //监听器
|
|
|
+ timeEvent() {
|
|
|
+ if (this.photoList.length == 0 || this.activeSection.learning == 1)
|
|
|
+ return;
|
|
|
+ let videoTime = this.player.j2s_getCurrentTime();
|
|
|
+ let photoTime = 0; //获取拍照秒数
|
|
|
+ for (let i = 0; i < this.photoList.length; i++) {
|
|
|
+ photoTime = Number(this.photoList[i]); //获取拍照秒数
|
|
|
+ if (photoTime < videoTime && photoTime > videoTime - 8) {
|
|
|
+ //3秒区间内才触发拍照,避免拉动滚动条
|
|
|
+ if (
|
|
|
+ this.photoHistoryList.indexOf(i) < 0 &&
|
|
|
+ this.activeSection.learning != 1
|
|
|
+ ) {
|
|
|
+ //不存在拍照历史,没有重修过,没有学过,则拍照
|
|
|
+ this.player.j2s_pauseVideo(); //暂停
|
|
|
+ this.photoIndex = i;
|
|
|
+ this.openPhoto(); //启动拍照
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //视频初次播放时触发
|
|
|
+ onPlayStatus() {
|
|
|
+ //计算拍照逻辑
|
|
|
+ this.photoLogic();
|
|
|
+ //开启上次播放位置提示
|
|
|
+ if (this.activeSection.videoCurrentTime) {
|
|
|
+ this.showRecordStatus = true;
|
|
|
+ this.showRecordSetTimeOut = setTimeout(() => {
|
|
|
+ this.showRecordStatus = false;
|
|
|
+ }, 5000);
|
|
|
+ }
|
|
|
+ console.log("视频初次播放时触发", this.player.j2s_getCurrentTime());
|
|
|
+ },
|
|
|
+ //视频暂停时触发
|
|
|
+ onVideoPause() {
|
|
|
+ console.log("视频暂停时触发");
|
|
|
+ },
|
|
|
+ //当前视频播放完毕时触发
|
|
|
+ onPlayOver() {
|
|
|
+ console.log("当前视频播放完毕时触发");
|
|
|
+ },
|
|
|
+ //播放出现错误时触发
|
|
|
+ onPlayerError() {
|
|
|
+ this.$message.error("播放出现错误时触发");
|
|
|
+ },
|
|
|
+ //发生业务逻辑错误
|
|
|
+ serverError() {
|
|
|
+ this.$message.error("发生业务逻辑错误");
|
|
|
+ },
|
|
|
+ //启动拍照
|
|
|
+ openPhoto() {}
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
@@ -40,5 +448,26 @@ export default {
|
|
|
height: 100%;
|
|
|
background: url() no-repeat center center;
|
|
|
background-size: contain;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.recordStyle {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 60px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ left: 8px;
|
|
|
+ background-color: rgba(0, 0, 0, 0.4);
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 24px;
|
|
|
+ user-select: none;
|
|
|
+
|
|
|
+ .videoCurrentTime_style {
|
|
|
+ display: inline-block;
|
|
|
+ width: 50px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .btn_sty {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|