Tang 2 tahun lalu
induk
melakukan
a6c2d659aa

+ 432 - 3
src/components/videoCy/index.vue

@@ -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>

+ 3 - 2
src/pages/course-detail/components/CourseTree.vue

@@ -309,7 +309,7 @@ export default {
                     level: item.level + 1,
                     type: 3,
                     name: i.name,
-                    courseId: i.courseId,
+                    courseId: item.courseId,
                     moduleId: i.moduleId,
                     chapterId: i.chapterId,
                     sectionId: i.sectionId,
@@ -426,8 +426,9 @@ export default {
     },
     //播放视频节
     watchSection(item) {
+      this.$bus.$emit("toPlay", item);
       // if (this.isActive(item)) return;
-      this.toPlay(item);
+      // this.toPlay(item);
     },
     toPlay(item) {},
     //回放或直播

+ 12 - 10
src/pages/course-detail/index.vue

@@ -81,21 +81,23 @@ export default {
           this.goodsData = res.data;
           //播放设置
           if (this.goodsData.goodsPlayConfig) {
-            this.goodsPlayConfig = JSON.parse(this.goodsData.goodsPlayConfig);
-            this.goodsPlayConfig.autoplay =
-              this.goodsPlayConfig.autoPlay > 0 ? true : false;
-            this.goodsPlayConfig.isAllowSeek =
-              this.goodsPlayConfig.drag > 0 ? "off" : "on";
-            this.goodsPlayConfig.playbackRate =
-              this.goodsPlayConfig.speed > 0 ? true : false;
+            var goodsPlayConfig = JSON.parse(this.goodsData.goodsPlayConfig);
+            goodsPlayConfig.autoplay =
+              goodsPlayConfig.autoPlay > 0 ? true : false;
+            goodsPlayConfig.isAllowSeek =
+              goodsPlayConfig.drag > 0 ? "off" : "on";
+            goodsPlayConfig.playbackRate =
+              goodsPlayConfig.speed > 0 ? true : false;
+            this.goodsData.goodsPlayConfig = goodsPlayConfig;
           }
           //拍照设置
           if (this.goodsData.goodsPhotographConfig) {
-            this.goodsPhotographConfig = JSON.parse(
+            var goodsPhotographConfig = JSON.parse(
               this.goodsData.goodsPhotographConfig
             );
-            this.goodsPhotographConfig.photoNum =
-              this.goodsPhotographConfig.photoNum || 0;
+            goodsPhotographConfig.photoNum =
+              goodsPhotographConfig.photoNum || 0;
+            this.goodsData.goodsPhotographConfig = goodsPhotographConfig;
           }
           resolve();
         });