index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <!-- <video ref="videoPlay" oncontextmenu="return false;" :src="safeUrl" :poster="coverUrl" @timeupdate="timeupdateAction" @ended="recordCommit(src)" controls controlslist="nodownload" disablePictureInPicture style="width: 100%; height: 100%"></video> -->
  3. <video-player
  4. v-if="hasUrl"
  5. ref="videoPlayer"
  6. class="video-player vjs-custom-skin"
  7. :playsinline="true"
  8. :options="playerOptions"
  9. @timeupdate="timeupdateAction"
  10. @ended="recordCommit(src)"
  11. />
  12. </template>
  13. <script>
  14. import {
  15. getVideoPlayInfo,
  16. saveWatchRecord
  17. } from '../../api/webApi/webVideo.js'
  18. export default {
  19. props: {
  20. aliIdType: {
  21. type: Number | String,
  22. default: ''
  23. },
  24. src: {
  25. type: String,
  26. default: ''
  27. }
  28. },
  29. data() {
  30. return {
  31. safeUrl: '',
  32. coverUrl: '/static/images/eval-center/img_fengminan.png',
  33. //
  34. playerOptions: {
  35. // playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
  36. autoplay: false, // 如果true,浏览器准备好时开始回放。
  37. muted: false, // 默认情况下将会消除任何音频。
  38. loop: false, // 导致视频一结束就重新开始。
  39. preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
  40. language: 'zh-CN',
  41. aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
  42. fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
  43. sources: [{ type: '', src: '' }],
  44. hls: true,
  45. poster: '', // 你的封面地址
  46. width: document.documentElement.clientWidth, // 播放器宽度
  47. notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
  48. controlBar: {
  49. timeDivider: true,
  50. durationDisplay: true,
  51. remainingTimeDisplay: false,
  52. fullscreenToggle: true // 全屏按钮
  53. }
  54. },
  55. // 播放统计日志字段
  56. recordCommitted: false,
  57. recordDuration: 0,
  58. recordPercent: 0
  59. }
  60. },
  61. computed: {
  62. hasUrl() {
  63. return this.playerOptions.sources?.length &&
  64. !!this.playerOptions.sources.first().src
  65. }
  66. },
  67. watch: {
  68. src: {
  69. handler: function(newV, oldV) {
  70. console.log('mx video received id:', newV)
  71. // save if needed
  72. this.recordCommit(oldV)
  73. this.toggleSrc(newV)
  74. // record reset
  75. this.recordReset()
  76. },
  77. immediate: true
  78. }
  79. },
  80. beforeDestroy() {
  81. this.recordCommit(this.src)
  82. },
  83. methods: {
  84. toggleSrc(videoId) {
  85. if (this.isPlayUrl(videoId)) {
  86. this.safeUrl = videoId
  87. this.setPlayerUrl(this.safeUrl)
  88. } else {
  89. this.getSafeUrl(videoId)
  90. }
  91. },
  92. getSafeUrl(id) {
  93. if (!id) return
  94. getVideoPlayInfo(id).then((res) => {
  95. this.coverUrl = res.data.coverUrl
  96. if (this.isPlayUrl(res.data.palyUrl)) {
  97. this.safeUrl = res.data.palyUrl
  98. this.setPlayerUrl(this.safeUrl, this.coverUrl)
  99. }
  100. this.recordCommitted = false // ensure committed status
  101. })
  102. },
  103. isPlayUrl(str) {
  104. return str?.toLowerCase().startsWith('http')
  105. },
  106. setPlayerUrl(url, poster) {
  107. let mediaType = 'video/mp4'
  108. if (url.toLowerCase().endsWith('m3u8')) {
  109. mediaType = 'application/x-mpegURL'
  110. }
  111. this.playerOptions.sources = [
  112. {
  113. src: url,
  114. type: mediaType
  115. }
  116. ]
  117. this.playerOptions.poster = poster || this.coverUrl
  118. },
  119. // 日志记录
  120. timeupdateAction(player) {
  121. const currentTime = player.currentTime()
  122. const duration = player.duration()
  123. this.recordDuration = duration
  124. this.recordPercent = 0
  125. if (this.recordDuration > 0) {
  126. this.recordPercent = (currentTime * 100) / duration
  127. }
  128. },
  129. recordReset() {
  130. this.recordCommitted = false
  131. this.recordDuration = 0
  132. this.recordPercent = 0
  133. },
  134. recordCommit(id) {
  135. console.log('record commit:', id)
  136. if (this.recordCommitted) return // 已提交
  137. if (!this.recordPercent) return // 无效数据
  138. if (this.recordPercent < 2) return // <3%播放太短,也不记,防止过度触发提交
  139. if(!this.aliIdType) return
  140. saveWatchRecord(
  141. id,
  142. this.recordDuration,
  143. this.recordPercent,
  144. this.aliIdType
  145. ).then((_) => {
  146. this.recordCommitted = true
  147. console.log('saveWatchRecord committed')
  148. })
  149. }
  150. },
  151. };
  152. </script>
  153. <style>
  154. </style>