y595705120 há 1 mês atrás
pai
commit
bf5a41b5ad
2 ficheiros alterados com 198 adições e 75 exclusões
  1. 1 0
      package.json
  2. 197 75
      src/containers/weixin/index.vue

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "default-passive-events": "^2.0.0",
     "element-ui": "^2.1.0",
     "es6-promise": "^4.2.8",
+    "hls.js": "^1.7.1",
     "js-md5": "^0.7.3",
     "node-sass": "^5.0.0",
     "sass-loader": "^10.1.0",

+ 197 - 75
src/containers/weixin/index.vue

@@ -4,19 +4,18 @@
     <div class="weixin-content-box">
       <div class="weixin-title">{{media.name|| tpl.name}}</div>
       <div class="weixin-content">
-        <video-player
-          id="myVideo1"
-          ref="videoPlayer"
-          :playsinline="true"
-          @pause="onPlayerPause($event)"
-          @timeupdate="onPlayerTimeupdate($event)"
-          @play="onPlayerStart($event)"
-          @ready="playerReadied"
-          @canplay="canpay($event)"
-          @ended="onPlayerEnded($event)"
-          :globalOptions="{controls:true}"
-          :options="options">
-        </video-player>
+       <video-player id="myVideo"
+       class="video-player-box"
+       ref="videoPlayer" :playsinline="true"
+         @pause="onPlayerPause($event)"
+         @timeupdate="onPlayerTimeupdate($event)"
+         @play="onPlayerStart($event)"
+         @ready="playerReadied"
+         @ended="onPlayerEnded($event)"
+         @error="onPlayerError($event)"
+         :globalOptions="{controls:true}"
+         :options="options">
+       </video-player>
         <div style="font-size: 16px;; margin: 10px auto;text-align: center;">
           <span>{{curTimes|useTime}}</span>
           <strong>/</strong>
@@ -29,7 +28,7 @@
 
     <!-- <div  style="width: 100%; margin: 0px auto;"> -->
     <div class="weixin-content-box" style="padding: 4px;">
-      <div class="weixin-content" v-for="item in list"  v-if="item.isFinish==0">
+      <div class="weixin-content" v-for="item in list" :key="item.id" v-if="item.isFinish==0">
         <div class="weixin-course-name">
           <el-button @click="loadMedia(item)" type="text">{{item.name}} </el-button>
         </div>
@@ -54,7 +53,7 @@
   import {
     videoPlayer
   } from 'vue-video-player';
-  // import 'video.js/dist/video-js.css'
+    import 'video.js/dist/video-js.css'
   import {
     httpServer
   } from "@/components/httpServer/httpServer.js";
@@ -110,6 +109,18 @@
         return hour + ":" + min + ":" + sec
       }
     },
+    beforeDestroy() {
+      this.stopTick()
+      if (this._seekTimer) clearTimeout(this._seekTimer)
+      this.reportErr("play", 'destroy');
+      document.removeEventListener("visibilitychange", this._onVisibilityChange)
+      document.removeEventListener("keydown", this._onKeyDown)
+    },
+    computed: {
+      player() {
+        return this.$refs.videoPlayer.player
+      },
+    },
     methods: {
        ...mapActions("user", ["loadBaseInfo"]),
       getCourse() {
@@ -123,11 +134,13 @@
               item.percent = getPercent(item)||0;
               return item;
             })
-            for( let i in this,list){
-              if( this.list[i].mediaId == this.userInfo.mediaId){
-                this.loadMedia( this.list[i])
-              }
-            }
+            // this.options.poster = tpl.tb
+            // for(let i=0; i<this.list.length; i++){
+            //   if( this.list[i].mediaId == this.userInfo.mediaId){
+            //     this.loadMedia( this.list[i])
+            //     break;
+            //   }
+            // }
           }
         })
       },
@@ -147,36 +160,71 @@
           that.reportErr("play", '' + err.message)
         }
       },
-      playerReadied(audio) {
+      playerReadied(player) {
+        let that = this;
         this.isReady = true
-        let myPlayer = this.$refs.videoPlayer.player;
-        myPlayer && myPlayer.play()
+
+        setTimeout(() => this.fixTouchEvents(player), 0);
+
+        if (this.media.position > 5) {
+          player.one('loadedmetadata', function () {
+            let pos = that.media.position
+            if (pos < player.duration()) {
+              that.setposition(pos)
+              that._seekTimer = setTimeout(function () {
+                if (!player.el_) return
+                player.currentTime(0)
+                player.play()
+              }, 15000)
+              player.one('seeked', function () {
+                clearTimeout(that._seekTimer)
+                that._seekTimer = null
+              })
+            }
+          })
+        }
+
+        setTimeout(() => {
+          if (that.player && that.player.volume) {
+            that.player.volume(that.volume)
+            that.player.muted(that.isMuted)
+          }
+        }, 1000)
+      },
+      fixTouchEvents(player) {
+        let slider = player.controlBar &&
+                     player.controlBar.progressControl &&
+                     player.controlBar.progressControl.seekBar
+        if (!slider) return
+        if (slider.handleTouchStart_) {
+          document.removeEventListener('touchstart', slider.handleTouchStart_)
+          document.addEventListener('touchstart', slider.handleTouchStart_, { passive: false })
+        }
+        if (slider.handleTouchMove_) {
+          document.removeEventListener('touchmove', slider.handleTouchMove_)
+          document.addEventListener('touchmove', slider.handleTouchMove_, { passive: false })
+        }
       },
       onPlayerTimeupdate(player) {
-        let myPlayer = this.$refs.videoPlayer.player;
+        let myPlayer = this.$refs.videoPlayer && this.$refs.videoPlayer.player;
+        if (!myPlayer) return;
         let curTimes = player.cache_.currentTime;
         this.curTimes = curTimes || 0
-        if (this.media.isFinish) {
-          return;
-        }
-      },
-      canpay(player){
-        console.log("player", this.media.position )
-        if( this.media.position > this.curTimes){
-          player.currentTime(this.media.position+3);
-          setTimeout( ()=>{player.play()}, 100)
-
-        }
       },
       setposition(position) {
-        if (position > this.media.duration) position = this.media.duration;
-        let player = this.$refs.videoPlayer.player;
-        player.currentTime(position);
-        player.play()
+        console.log("setposition", position)
+        let player = this.$refs.videoPlayer && this.$refs.videoPlayer.player;
+        if (!player || !player.el_) return;
+        let dur = this.media.duration
+        if (position > dur) position = dur;
+        console.log("currentTime", position)
         if (this.media.isFinish) return;
-        if (this.media.position >= this.media.duration - 10 && !this.media.isFinish) {
+        if (position >= dur - 10 && !this.media.isFinish) {
           this.tick(true)
+        }else{
+          player.currentTime(position);
         }
+        // this.onPlay = true
       },
       onPlayerPause(event) {
         this.reportErr("play", 'pause');
@@ -193,28 +241,54 @@
         this.$emit("close")
       },
       doPause() {
-        // console.log("doPause")
+        console.log("doPause")
         this.stopTick()
         this.onPlay = false
         let myPlayer = this.$refs.videoPlayer.player;
         myPlayer && myPlayer.pause()
       },
       doPlay() {
-        console.log("doPlay")
         this.onPlay = true
         this.startTick();
         if (!this.$refs.videoPlayer || !this.$refs.videoPlayer.player) return;
         if (!this.dialog) return this.doPause();
         let myPlayer = this.$refs.videoPlayer.player;
-        myPlayer && myPlayer.play()
+        let p = myPlayer && myPlayer.play()
+        if (p && p.catch) p.catch(function() {
+          console.log('doPay', p)
+        })
         this.tickNum = 0
       },
+      setVolume(val) {
+        this.volume = val
+        this.isMuted = val === 0
+        if (this.player && this.player.volume) {
+          this.player.volume(val)
+          this.player.muted(this.isMuted)
+        }
+      },
+      toggleMute() {
+        this.isMuted = !this.isMuted
+        if (this.player && this.player.volume) {
+          this.player.muted(this.isMuted)
+        }
+      },
       onPlayerStart() {
-        console.log("onPlayerStart")
+        // console.log("onPlayerStart")
         this.reportErr("play", 'start');
         this.startTick();
         this.onPlay = true
       },
+      startMonitor() {
+        this._onVisibilityChange = () => {
+          if (document.visibilityState == "hidden") {
+            this.reportErr("play", 'hidden');
+          } else {
+            this.reportErr("play", 'show');
+          }
+        }
+        document.addEventListener("visibilitychange", this._onVisibilityChange);
+      },
       reportErr(action, msg) {
         httpServer("course.report", {
           action,
@@ -224,25 +298,42 @@
       tick(force = false) {
         let media = this.media;
         this.tickNum++
+        // 检测卡死:两次 tick 无进度则跳过 5 秒
+        let myPlayer = this.$refs.videoPlayer && this.$refs.videoPlayer.player;
+        if (myPlayer) {
+          let now = parseInt(myPlayer.currentTime())
+          if (this._lastCurTime !== undefined && now === this._lastCurTime && this.onPlay) {
+            this._stuckCount = (this._stuckCount || 0) + 1
+            if (this._stuckCount >= 2) {
+              this._stuckCount = 0
+              let skip = now + 5
+              console.log("stuck skip to", skip)
+              myPlayer.currentTime(skip)
+            }
+          } else {
+            this._stuckCount = 0
+          }
+          this._lastCurTime = now
+        }
+        // 已经完成
         if (this.media.isFinish) {
           console.log("finish")
           return;
         }
         // 主动暂停
-        let myPlayer = this.$refs.videoPlayer.player;
-        let curTimes = parseInt(myPlayer.currentTime());
-        // 后退无心跳
-        if (this.media.position > curTimes && !force) return;
+        if (!myPlayer) return;
+
+        let curTimes = this._lastCurTime
         if (curTimes < 4) {
           console.log("curTimes")
           return;
         }
-
-        let isFinish = force ? 1 : 0
-        if (curTimes >= media.duration) isFinish = 1;
+        let isFinish = media.isFinish||0;
+        if (curTimes >= media.duration-15) isFinish = 1;
         //  拉到后面
         if (!isFinish) {
           if (!this.onPlay) return;
+          if(curTimes <= media.position) return;
         }
         if(window.navigator.webdriver){
           this.reportErr("play", 'webdriver');
@@ -253,29 +344,37 @@
         let param = {
           id: media.id,
           position: curTimes,
-          isFinish
+          isFinish,
+          force
         };
         httpServer("course.tick", param, true).then(res => {
-          if (res.code == 200) {
-            let {
-              skip,
-              position,
-              pause,
-              closed
-            } = res.data
-            if (pause || closed) {
-              this.doPause();
-              this.$emit("close")
-              if (closed) {
-                this.$message.errorMsg("禁止多处同时学习", 5);
-              } else if (pause) {
-                this.$message.errorMsg("禁止多处同时学习", 5);
-              }
-              return
+          if (res.code != 200) return;
+          let {
+            skip,
+            position,
+            pause,
+            msg,
+            closed
+          } = res.data
+          if (pause || closed) {
+            this.doPause();
+            this.$emit("close")
+            if (closed) {
+              this.$message.errorMsg(msg||"禁止多处同时学习", 5);
+            } else if (pause) {
+              this.$message.errorMsg(msg||"禁止多处同时学习", 5);
+            }
+            return
+          }
+          if (!skip) {
+            let diff = Math.abs(position - curTimes);
+            if (diff > 5) {
+              this.setposition(position);
             }
-            if (!skip) this.setposition(position);
-            Object.assign(this.media, res.data)
           }
+          Object.assign(param, res.data)
+          this.$emit("update", param)
+
         })
       },
       loadMedia( item ) {
@@ -287,11 +386,18 @@
           this.media.position = position;
           this.media.duration = duration;
           this.media.id = id;
-          this.options.sources = [{src:this.mediaUrl,type: "application/x-mpegURL"}];
-          this.options.playtimes = position||1;
-          this.options.autoplay  = position>0;
-          this.curTimes = 0
-          this.$refs.player && this.$refs.player.preload()
+          this.options = {
+            ...this.options,
+            sources: [{src:mediaUrl,type: "application/x-mpegURL"}],
+            playtimes: position||0,
+            html5: {
+              hls: {
+                overrideNative: true
+              }
+            },
+            autoplay: true
+          }
+          this.curTimes = 0;
         });
       }
     },
@@ -313,4 +419,20 @@
 </script>
 <style>
   @import url("./index.css");
+  .video-js {
+    touch-action: none;
+    .vjs-control-bar {
+      .vjs-icon-custombutton {
+        font-family: VideoJS;
+        font-weight: normal;
+        font-style: normal;
+      }
+
+      .vjs-icon-custombutton:before {
+        content: "\f108";
+        font-size: 1.8em;
+        line-height: 1.67;
+      }
+    }
+  }
 </style>