media.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. <template>
  2. <div>
  3. <!-- -->
  4. <div class="v-wrap-marks"></div>
  5. <video-player id="myVideo" class="video-player-box" ref="videoPlayer" :playsinline="true"
  6. @pause="onPlayerPause($event)" @timeupdate="onPlayerTimeupdate($event)" @play="onPlayerStart($event)"
  7. @ready="playerReadied" @ended="onPlayerEnded($event)" :globalOptions="{controls:true}" :options="options">
  8. </video-player>
  9. <div class="dialog-footer pt30">
  10. <el-row class="media-footer">
  11. <el-col :span="10" class="media-time">
  12. <span>{{curTimes|useTime}}</span>
  13. <strong>/</strong>
  14. <span>{{media.duration|useTime}}</span>
  15. </el-col>
  16. <el-col :span="4" class="media-center">
  17. <el-button class="bicon" v-if="!onPlay" type="primary" @click="doPlay" icon="el-icon-video-play"
  18. circle></el-button>
  19. <el-button class="bicon" v-else type="warning" @click="doPause" icon="el-icon-video-pause" circle></el-button>
  20. </el-col>
  21. <el-col :span="10" class="media-select">
  22. <el-button class="bicon" type="danger" icon="el-icon-close" @click="onClose" style="float: right;">
  23. </el-button>
  24. <div style="margin-top:0px;float: right;">
  25. <el-select placeholder="流畅" :value="mediaType" class="media-el-select"
  26. @change="(val)=>{$emit('changeMedia', val)}">
  27. <el-option label="流畅" value="ld"></el-option>
  28. <el-option label="标清" value="hls"></el-option>
  29. </el-select>
  30. </div>
  31. </el-col>
  32. </el-row>
  33. </div>
  34. </div>
  35. </template>
  36. <script>
  37. import {
  38. httpServer
  39. } from "@/components/httpServer/httpServer.js";
  40. import md5 from 'js-md5';
  41. import {
  42. videoPlayer
  43. } from 'vue-video-player';
  44. import 'video.js/dist/video-js.css'
  45. import {
  46. MessageBox
  47. } from "element-ui";
  48. export default {
  49. name: "Index",
  50. data() {
  51. return {
  52. timer: false,
  53. tickNum: 0,
  54. prevTime: 0,
  55. isReady: false,
  56. curTimes: 0,
  57. onPlay: false
  58. }
  59. },
  60. components: {
  61. videoPlayer
  62. },
  63. watch: {
  64. mediaType() {
  65. if (!this.mediaType) return;
  66. },
  67. dialog(showDilog) {
  68. if (!showDilog) {
  69. this.doPause()
  70. this.isReady = false
  71. }
  72. }
  73. },
  74. props: {
  75. mediaType: {
  76. type: String,
  77. default: ''
  78. },
  79. media: {
  80. type: Object,
  81. default: () => {
  82. return {
  83. id: '',
  84. percent: 0
  85. }
  86. }
  87. },
  88. dialog: {
  89. type: Boolean,
  90. default: true
  91. },
  92. options: {
  93. type: Object,
  94. default: () => {
  95. return {}
  96. }
  97. }
  98. },
  99. mounted() {
  100. setTimeout(() => {
  101. this.$emit("updateOption", {
  102. muted: false
  103. })
  104. }, 3000)
  105. },
  106. filters: {
  107. useTime(val) {
  108. let timestr = ""
  109. let hour = parseInt(val / 3600);
  110. let min = parseInt(val / 60 % 60);
  111. let sec = parseInt(val % 60);
  112. if (hour < 10) hour = "0" + hour;
  113. if (min < 10) min = "0" + min;
  114. if (sec < 10) sec = "0" + sec;
  115. return hour + ":" + min + ":" + sec
  116. }
  117. },
  118. beforeDestroy() {
  119. this.stopTick()
  120. this.reportErr("play", 'destroy');
  121. },
  122. computed: {
  123. player() {
  124. return this.$refs.videoPlayer.player
  125. }
  126. },
  127. created() {
  128. this.startTick()
  129. this.startMonitor()
  130. },
  131. methods: {
  132. setMarks() {
  133. console.log("setMarks")
  134. if (!this.options.marks) return;
  135. var div = document.getElementById('myVideo')
  136. var div1 = div.firstChild
  137. var div3 = document.createElement("div");
  138. div3.setAttribute("class", "resize-drag");
  139. if (this.mediaType == 'ld') {
  140. div3.style.cssText =
  141. "position:absolute;top:52px;left:10px; background-color: #f4f4f4;width:50px; height:50px;border-radius: 50%;";
  142. } else {
  143. div3.style.cssText =
  144. "position:absolute;top:80px;left:18px; background-color: #f4f4f4;width:50px; height:50px;border-radius: 50%;";
  145. }
  146. div1.appendChild(div3)
  147. },
  148. startTick() {
  149. let tick = this.tryTick;
  150. if (this.timer) clearInterval(this.timer);
  151. this.timer = setInterval(tick, 5 * 1000);
  152. },
  153. stopTick() {
  154. if (this.timer) clearInterval(this.timer);
  155. },
  156. tryTick() {
  157. let that = this;
  158. try {
  159. that.tick()
  160. } catch (err) {
  161. that.reportErr("play", '' + err.message)
  162. }
  163. },
  164. playerReadied(audio) {
  165. console.log("playerReadied", audio)
  166. let that = this;
  167. if (this.media.position > 5 && this.media.position < this.media.duration) {
  168. this.setposition(this.media.position+3)
  169. }
  170. this.isReady = true
  171. setTimeout(() => this.setMarks(), 600);
  172. },
  173. onPlayerTimeupdate(player) {
  174. let myPlayer = this.$refs.videoPlayer.player;
  175. let curTimes = player.cache_.currentTime;
  176. this.curTimes = curTimes || 0
  177. if (this.media.isFinish) {
  178. return;
  179. }
  180. },
  181. setposition(position) {
  182. console.log("setposition", position)
  183. if (position > this.media.duration) position = this.media.duration;
  184. let player = this.$refs.videoPlayer.player;
  185. player.currentTime(position);
  186. if (this.media.isFinish) return;
  187. if (this.media.position >= this.media.duration - 10 && !this.media.isFinish) {
  188. this.tick(true)
  189. }
  190. // this.onPlay = true
  191. },
  192. onPlayerPause(event) {
  193. this.reportErr("play", 'pause');
  194. this.stopTick()
  195. this.onPlay = false
  196. },
  197. onPlayerEnded(event) {
  198. this.reportErr("play", 'end');
  199. this.tick(true)
  200. },
  201. onClose() {
  202. this.reportErr("play", 'close')
  203. this.doPause()
  204. this.$emit("close")
  205. },
  206. doPause() {
  207. // console.log("doPause")
  208. this.stopTick()
  209. this.onPlay = false
  210. let myPlayer = this.$refs.videoPlayer.player;
  211. myPlayer && myPlayer.pause()
  212. },
  213. doPlay() {
  214. // console.log("doPlay")
  215. this.onPlay = true
  216. this.startTick();
  217. if (!this.$refs.videoPlayer || !this.$refs.videoPlayer.player) return;
  218. if (!this.dialog) return this.doPause();
  219. let myPlayer = this.$refs.videoPlayer.player;
  220. myPlayer && myPlayer.play()
  221. this.tickNum = 0
  222. },
  223. onPlayerStart() {
  224. // console.log("onPlayerStart")
  225. this.reportErr("play", 'start');
  226. this.startTick();
  227. this.onPlay = true
  228. },
  229. startMonitor() {
  230. let that = this
  231. document.addEventListener("visibilitychange", function() {
  232. // || document.hidden
  233. if (document.visibilityState == "hidden") {
  234. // that.doPause( )
  235. that.reportErr("play", 'hidden');
  236. } else {
  237. that.reportErr("play", 'show');
  238. // that.doPlay()
  239. }
  240. });
  241. // 监听F12
  242. document.addEventListener("keydown", function(e) {
  243. if (e.key == "F12") {
  244. that.reportErr("play", 'keydownF12');
  245. e.preventDefault();
  246. }
  247. });
  248. // setInterval(function() { check() }, 1000);
  249. // var check = function() {
  250. // function doCheck(a) {
  251. // if (("" + a / a)["length"] !== 1 || a % 20 === 0) {
  252. // (function() {}
  253. // ["constructor"]("debugger")())
  254. // } else {
  255. // (function() {}
  256. // ["constructor"]("debugger")())
  257. // }
  258. // doCheck(++a)
  259. // }
  260. // try {
  261. // doCheck(0)
  262. // } catch (err) {}
  263. // };
  264. },
  265. // startMonitor() {
  266. // let that = this
  267. // window.onblur = function() {
  268. // that.doPause()
  269. // }
  270. // window.onfocus = function () {
  271. // that.doPlay()
  272. // }
  273. // },
  274. tickWait() {
  275. this.doPause()
  276. let that = this
  277. MessageBox({
  278. title: "连续学习超15分钟",
  279. message: "是否继续学习",
  280. showCancelButton: true,
  281. confirmButtonText: "确定",
  282. cancelButtonText: "取消",
  283. beforeClose: (action, instance, done) => {
  284. if (action === "confirm") {
  285. that.doPlay();
  286. done();
  287. } else {
  288. done();
  289. }
  290. }
  291. })
  292. },
  293. reportErr(action, msg) {
  294. httpServer("course.report", {
  295. action,
  296. msg
  297. })
  298. },
  299. tick(force = false) {
  300. let media = this.media;
  301. this.tickNum++
  302. // 已经完成
  303. if (this.media.isFinish) {
  304. console.log("finish")
  305. return;
  306. }
  307. // 主动暂停
  308. let myPlayer = this.$refs.videoPlayer.player;
  309. let curTimes = parseInt(myPlayer.currentTime());
  310. // 后退无心跳
  311. if (!force && this.media.position > (curTimes+8)){
  312. return;
  313. }
  314. if (curTimes < 4) {
  315. console.log("curTimes")
  316. return;
  317. }
  318. let isFinish = force ? 1 : 0
  319. if (curTimes >= media.duration-15) isFinish = 1;
  320. // 拉到后面
  321. if (!isFinish) {
  322. if (!this.onPlay) return;
  323. }
  324. if(window.navigator.webdriver){
  325. this.reportErr("play", 'webdriver');
  326. this.doPause()
  327. return
  328. }
  329. // 强制完成
  330. let param = {
  331. id: media.id,
  332. position: curTimes,
  333. isFinish
  334. };
  335. httpServer("course.tick", param, true).then(res => {
  336. if (res.code == 200) {
  337. let {
  338. skip,
  339. position,
  340. pause,
  341. closed
  342. } = res.data
  343. if (pause || closed) {
  344. this.doPause();
  345. this.$emit("close")
  346. if (closed) {
  347. this.$message.errorMsg("禁止多处同时学习", 5);
  348. } else if (pause) {
  349. this.$message.errorMsg("禁止多处同时学习", 5);
  350. }
  351. return
  352. }
  353. if (!skip) this.setposition(position);
  354. Object.assign(param, res.data)
  355. this.$emit("update", param)
  356. }
  357. })
  358. }
  359. }
  360. }
  361. </script>
  362. <style>
  363. .video-js {
  364. .vjs-control-bar {
  365. .vjs-icon-custombutton {
  366. font-family: VideoJS;
  367. font-weight: normal;
  368. font-style: normal;
  369. }
  370. .vjs-icon-custombutton:before {
  371. content: "\f108";
  372. font-size: 1.8em;
  373. line-height: 1.67;
  374. }
  375. }
  376. }
  377. .p-process {
  378. width: 100%;
  379. margin: 20px auto;
  380. height: 30px;
  381. }
  382. .media-footer {
  383. padding: 0px 30px;
  384. text-align: left;
  385. line-height: 40px !important;
  386. bottom: -10px;
  387. }
  388. .media-center {
  389. text-align: center;
  390. padding: 0px;
  391. }
  392. .media-time {
  393. font-size: 18px;
  394. vertical-align: center;
  395. }
  396. .media-select {
  397. white-space: nowrap;
  398. text-align: right;
  399. line-height: 40px !important;
  400. float: right;
  401. margin: 0px !important;
  402. }
  403. .bicon {
  404. font-size: 28px !important;
  405. padding: 4px !important;
  406. }
  407. .media-el-select {
  408. font-size: 28px !important;
  409. width: 80px;
  410. padding: -4px auto !important;
  411. }
  412. </style>