task_info.html 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. {extend name="public/container"}
  2. {block name="head_top"}
  3. <script src="{__WAP_PATH}zsff/js/md5.js"></script>
  4. <link rel="stylesheet" href="//g.alicdn.com/de/prismplayer/2.9.3/skins/default/aliplayer-min.css">
  5. <script src="//g.alicdn.com/de/prismplayer/2.9.3/aliplayer-min.js"></script>
  6. <script type="text/javascript" src="//g.alicdn.com/de/prismplayer/2.9.3/hls/aliplayer-hls-min.js"></script>
  7. <script src="//g.alicdn.com/de/prismplayer/2.9.3/hls/aliplayer-vod-min.js"></script>
  8. <!--<script src="//g.alicdn.com/de/prismplayer/2.8.8/hls/aliplayer-vod-anti-min.js"></script>页面防调试js-->
  9. <style>
  10. body {
  11. background-color: #f5f5f5;
  12. }
  13. .knowledge{
  14. width: .86rem;
  15. font-size: .3rem;
  16. text-align: center;
  17. color: #ccc;
  18. }
  19. </style>
  20. {/block}
  21. {block name="content"}
  22. <div v-cloak id="app">
  23. <div class="task-info">
  24. <div v-if="taskInfo.type !== 1" id="player" :style="{ height: playerHeight + 'px' }" class="prism-player" :hidden="taskInfo.type === 2"></div>
  25. <div v-if="taskInfo.type !== 3" :style="{ height: playerHeight + 'px' }" class="banner">
  26. <img :src="taskInfo.image">
  27. </div>
  28. <div class="intro">
  29. <div>{{ taskInfo.title }}</div>
  30. <div>已播放{{ taskInfo.play_count }}次</div>
  31. </div>
  32. <div v-if="taskInfo.type === 2" class="audio-custom">
  33. <div class="progress">
  34. <div class="time">{{ audioPlayer.currentTime | format }}</div>
  35. <div ref="bar" class="bar" @click="audioSeek">
  36. <div :style="{ width: audioPlayer.range + '%' }" class="range" @touchmove.self="audioSeeking" @touchend="audioSeekEnd">
  37. <div class="dot"></div>
  38. </div>
  39. </div>
  40. <div class="time">{{ audioPlayer.duration | format }}</div>
  41. </div>
  42. <div class="control">
  43. <button class="knowledge iconleft" type="button" @click="audioPrev"></button>
  44. <button type="button" @click="audioPlay">
  45. <svg class="icon" aria-hidden="true">
  46. <use :xlink:href="audioPlayer.paused ? '#iconbofang1' : '#iconzanting'"></use>
  47. </svg>
  48. </button>
  49. <button class="knowledge iconright" type="button" @click="audioNext"></button>
  50. </div>
  51. <audio ref="audio" :src="audioPlayer.src" @durationchange="onAudioDurationChange($event)" @timeupdate="onAudioTimeUpdate" @ended="onAudioEnded">您的浏览器不支持 H5 audio</audio>
  52. </div>
  53. <div class="video_tab acea-row row-around">
  54. <div :class="{ on: type === 0 }" class="item" @click="type = 0">详情</div>
  55. <div :class="{ on: type === 1 }" class="item" @click="type = 1">目录</div>
  56. </div>
  57. <div v-show="type === 0" class="content" v-html="taskInfo.content"></div>
  58. <div v-show="type === 1" class="video_list">
  59. <ul class="catalogue">
  60. <li v-for="(item, index) in taskList" :key="item.id" :class="{ gray: item.taskTrue }"
  61. @click="play(item)">
  62. <div class="image">
  63. <img v-if="item.type === 1" class="img" src="{__WAP_PATH}zsff/images/media1.png">
  64. <img v-else-if="item.type === 2" class="img" src="{__WAP_PATH}zsff/images/media2.png">
  65. <img v-else-if="item.type === 3 || item.type === 4" class="img"
  66. src="{__WAP_PATH}zsff/images/media3.png">
  67. </div>
  68. <div class="title">{{index < 9 ? '0' + (index + 1) : index + 1}} | {{item.title}}</div>
  69. <template v-if="item.is_free">
  70. <div v-if="item.pay_status" class="knowledge iconsuozi"></div>
  71. <div v-else class="knowledge iconziyuan2"></div>
  72. </template>
  73. <div v-else class="free">免费</div>
  74. </li>
  75. </ul>
  76. <p class="loading-line" style="background-color: #fff">
  77. <span v-show="loading == true" class="fa fa-spinner loadingpic" style="font-size: 0.4rem"></span>
  78. <span v-text="loadTitle">{{loadTitle}}</span>
  79. </p>
  80. </div>
  81. </div>
  82. <shortcut></shortcut>
  83. </div>
  84. {/block}
  85. {block name='foot'}
  86. <script>
  87. var taskInfo = {$taskInfo},
  88. specialId = {$specialId},
  89. specialInfo = {$specialInfo},
  90. isPay = {$isPay? 'true': 'false'},
  91. isMember = {$is_member},uid={$userInfo['uid'] ? $userInfo['uid']:0};
  92. require(['vue', 'helper', 'store', '{__WAP_PATH}zsff/js/shortcut.js'], function (Vue, $h, api) {
  93. var app = new Vue({
  94. el: '#app',
  95. filters: {
  96. format: function (time) {
  97. if (!time) {
  98. return '00:00';
  99. }
  100. var minutes = Math.floor(time / 60),
  101. seconds = Math.floor(time % 60);
  102. if (minutes < 10) {
  103. minutes = '0' + minutes;
  104. }
  105. if (seconds < 10) {
  106. seconds = '0' + seconds;
  107. }
  108. return minutes + ':' + seconds;
  109. }
  110. },
  111. data: {
  112. taskInfo: taskInfo,
  113. specialInfo: specialInfo,
  114. isMember: isMember ? isMember : 0,
  115. taskList: [],
  116. type: 0,
  117. where: {
  118. page: 1,
  119. limit: 10,
  120. special_id: specialId,
  121. },
  122. is_pay: isPay,
  123. loading: false,
  124. loadend: false,
  125. loadTitle: '上拉加载更多',
  126. bannerImg: '',
  127. audio: null,
  128. audioBar: null,
  129. audioPlayer: {
  130. src: taskInfo.link,
  131. currentIndex: 0,
  132. currentTime: 0,
  133. duration: 0,
  134. range: 0,
  135. paused: true
  136. },
  137. currentMedia: null,
  138. screenWidth: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
  139. timer: null,
  140. player: null
  141. },
  142. computed: {
  143. playerHeight: function () {
  144. return this.screenWidth * 9 / 16;
  145. }
  146. },
  147. watch: {
  148. 'audioPlayer.src': function () {
  149. this.bannerImg = this.taskList[this.audioPlayer.currentIndex].image;
  150. },
  151. currentMedia: function () {
  152. clearTimeout(this.timer);
  153. }
  154. },
  155. created: function () {
  156. document.title = this.taskInfo.title;
  157. this.getCourseList();
  158. },
  159. mounted: function () {
  160. var that=this;
  161. this.$nextTick(function () {
  162. this.timer = setTimeout(() => {
  163. this.setMemory(30);
  164. clearTimeout(this.timer);
  165. }, 30000);
  166. if (this.taskInfo.type === 1) {
  167. return;
  168. }
  169. if (this.taskInfo.link && !this.taskInfo.videoId) {
  170. this.audio = this.$refs.audio;
  171. this.createPlayer();
  172. } else if(this.taskInfo.videoId && !this.taskInfo.link){
  173. this.callPlayAuth();
  174. }
  175. });
  176. mapleWx($jssdk(), function () {
  177. this.onMenuShareAll({
  178. title: that.taskInfo.title,
  179. desc: that.taskInfo.title,
  180. imgUrl: that.taskInfo.image,
  181. link: location.href.indexOf('?') == -1 ? location.href + '?spread_uid=' + uid : location.href + '&spread_uid=' + uid,
  182. });
  183. });
  184. },
  185. destroyed: function () {
  186. this.player.dispose();
  187. },
  188. methods: {
  189. // 音频时长
  190. onAudioDurationChange: function (event) {
  191. var duration = event.target.duration;
  192. this.audioPlayer.duration = duration;
  193. },
  194. // 音频播放进度
  195. onAudioTimeUpdate: function (event) {
  196. var target = event.target,
  197. currentTime = target.currentTime;
  198. this.audioPlayer.currentTime = currentTime;
  199. this.audioPlayer.range = Math.floor(currentTime / target.duration * 100);
  200. },
  201. // 拖动音频进度条
  202. audioSeeking: function (event) {
  203. var range = (event.targetTouches[0].pageX - event.target.offsetLeft) / this.audioBar.offsetWidth * 100;
  204. this.audioPlayer.paused = true;
  205. if (range > 100) {
  206. range = 100;
  207. }
  208. this.audioPlayer.range = range;
  209. if(this.taskInfo.videoId) {
  210. this.player.pause();
  211. }else{
  212. this.audioPlayer.paused ? this.audio.pause() : this.audio.play();
  213. }
  214. },
  215. // 拖动音频进度条结束
  216. audioSeekEnd: function () {
  217. this.audioPlayer.paused = false;
  218. if(this.taskInfo.videoId) {
  219. var time = this.player.getDuration() * this.audioPlayer.range / 100;
  220. this.player.seek(time);
  221. this.player.play();
  222. }else{
  223. this.audio.currentTime = this.audio.duration * this.audioPlayer.range / 100;
  224. this.audioPlayer.paused ? this.audio.pause() : this.audio.play();
  225. }
  226. },
  227. // 点击音频进度条
  228. audioSeek: function (event) {
  229. this.audioPlayer.paused = false;
  230. if(this.taskInfo.videoId){
  231. var range = event.offsetX / this.audioBar.offsetWidth,
  232. currentTime = this.player.getDuration() * range;
  233. this.audioPlayer.range = range * 100;
  234. this.player.seek(currentTime);
  235. this.player.play();
  236. }else{
  237. var range = event.offsetX / this.audioBar.offsetWidth,
  238. currentTime = this.audio.duration * range;
  239. this.audioPlayer.range = range * 100;
  240. this.audio.currentTime = currentTime;
  241. this.audioPlayer.paused ? this.audio.pause() : this.audio.play();
  242. }
  243. },
  244. // 音频播放/暂停
  245. audioPlay: function () {
  246. this.audioPlayer.paused = !this.audioPlayer.paused;
  247. if(this.taskInfo.videoId){
  248. this.audioPlayer.paused ? this.player.pause() : this.player.play();
  249. }else{
  250. this.audioPlayer.paused ? this.audio.pause() : this.audio.play();
  251. }
  252. },
  253. // 音频播放结束
  254. onAudioEnded: function () {
  255. this.audioPlayer.paused = true;
  256. this.audioPlayer.paused ? this.audio.pause() : this.audio.play();
  257. },
  258. // 音频上一首
  259. audioPrev: function () {
  260. var that=this;
  261. var taskListLength = that.taskList.length,
  262. currentIndex = that.audioPlayer.currentIndex,
  263. currentTask;
  264. for(var i=0;i<taskListLength;i++){
  265. if(that.taskList[i].id==that.taskInfo.id){
  266. currentIndex=i;
  267. }
  268. }
  269. if(currentIndex>0){
  270. currentIndex=Number(currentIndex)-1;
  271. }else{
  272. return $h.pushMsgOnce('当前已是第一首');
  273. }
  274. currentTask = that.taskList[currentIndex];
  275. if (currentTask.pay_status) {
  276. return $h.pushMsgOnce('请购买后再播放');
  277. }
  278. that.play(currentTask);
  279. },
  280. // 音频下一首
  281. audioNext: function () {
  282. var that=this;
  283. var taskListLength = that.taskList.length,
  284. currentIndex = that.audioPlayer.currentIndex,
  285. currentTask;
  286. for(var i=0;i<taskListLength;i++){
  287. if(that.taskList[i].id==that.taskInfo.id){
  288. currentIndex=i;
  289. }
  290. }
  291. currentIndex=Number(currentIndex)+1;
  292. if(currentIndex==taskListLength){
  293. return $h.pushMsgOnce('当前已是最好一首');
  294. }
  295. currentTask = that.taskList[currentIndex];
  296. if (currentTask.pay_status) {
  297. return $h.pushMsgOnce('请购买后再播放');
  298. }
  299. that.play(currentTask);
  300. },
  301. // 播放记忆
  302. setMemory: function (time) {
  303. var id = this.currentMedia ? this.currentMedia.id : this.taskInfo.id;
  304. api.baseGet($h.U({ c: 'special', a: 'viewing', q: { special_id: this.where.special_id, task_id: id, time: time } }));
  305. },
  306. play: function (item) {
  307. if (this.specialInfo.pay_type == 1 && item.pay_status == 1 && this.is_pay == false) return $h.pushMsgOnce('请先购买~');
  308. if (item.is_pay == 2) {
  309. this.password = true;
  310. this.studio_pwd = item.studio_pwd;
  311. this.stream_name = item.stream_name;
  312. return;
  313. }
  314. var that = this;
  315. that.currentMedia = item;
  316. api.baseGet($h.U({ c: 'special', a: 'get_task_link', q: { task_id: item.id, special_id: item.special_id } }), function (res) {
  317. if (item.type == 4) {
  318. window.location.href = $h.U({ c: 'live', a: 'index', q: { stream_name: item.stream_name } });
  319. } else {
  320. api.baseGet($h.U({ c: 'special', a: 'play_num', q: { task_id: item.id, special_id: item.special_id } }));
  321. if(res.data.code==200){
  322. if (item.type==1) {
  323. window.location.href = $h.U({ c: "special", a: "task_text_info", q: { id: item.id, specialId: item.special_id } });
  324. } else {
  325. window.location.href = $h.U({ c: "special", a: "task_info", q: { id: item.id, specialId: item.special_id } });
  326. }
  327. }else {
  328. return $h.showMsg('更新数据有误!');
  329. }
  330. }
  331. }, function (err) {
  332. return $h.pushMsgOnce(err);
  333. })
  334. },
  335. //滑动底部加载
  336. bScrollInit: function () {
  337. var that = this;
  338. $h.EventUtil.listenTouchDirection(document, function () {
  339. that.loading == false && that.getCourseList();
  340. }, false);
  341. },
  342. getCourseList: function () {
  343. var that = this;
  344. if (this.loading) return;
  345. if (this.loaded) return;
  346. this.loadTitle = '';
  347. this.loading = true;
  348. api.baseGet($h.U({ c: 'special', a: 'get_course_list', q: this.where }), function (res) {
  349. var data = res.data.data;
  350. var list = data.list || [];
  351. this.taskList = this.taskList.concat(list);
  352. this.where.page = data.page;
  353. this.loaded = list.length < this.where.limit;
  354. this.loadTitle = this.loaded ? '我也是有底线的' : '上拉加载更多';
  355. this.loading = false;
  356. this.$nextTick(function () {
  357. this.bScrollInit();
  358. });
  359. }.bind(this), function (res) {
  360. that.loading = false;
  361. that.loadTitle = '加载更多';
  362. });
  363. },
  364. // 创建播放器
  365. createPlayer: function () {
  366. var that=this;
  367. if (that.taskInfo.type === 2) {
  368. that.audio = that.$refs.audio;
  369. that.audioBar = that.$refs.bar;
  370. } else {
  371. that.player = new Aliplayer({
  372. id: 'player',
  373. source: that.taskInfo.link,
  374. cover: that.taskInfo.image,
  375. autoplay: false,
  376. skinLayout: [
  377. { name: "bigPlayButton", align: "cc" },
  378. {
  379. name: "H5Loading", align: "cc"
  380. },
  381. { name: "errorDisplay", align: "tlabs", x: 0, y: 0 },
  382. { name: "infoDisplay" },
  383. { name: "tooltip", align: "blabs", x: 0, y: 56 },
  384. { name: "thumbnail" },
  385. {
  386. name: "controlBar", align: "blabs", x: 0, y: 0,
  387. children: [
  388. { name: "progress", align: "blabs", x: 0, y: 44 },
  389. { name: "playButton", align: "tl", x: 15, y: 12 },
  390. { name: "timeDisplay", align: "tl", x: 10, y: 7 },
  391. { name: "fullScreenButton", align: "tr", x: 10, y: 12 },
  392. { name: "subtitle", align: "tr", x: 15, y: 12 },
  393. { name: "setting", align: "tr", x: 15, y: 12 },
  394. { name: "volume", align: "tr", x: 5, y: 10 }
  395. ]
  396. }
  397. ]
  398. });
  399. }
  400. },
  401. // 获取播放凭证
  402. callPlayAuth: function () {
  403. $h.loadFFF();
  404. api.baseGet($h.U({
  405. c: 'special',
  406. a: 'get_video_playback_credentials',
  407. p: {
  408. type: 2,
  409. videoId: this.taskInfo.videoId
  410. }
  411. }), function (res) {
  412. this.getPlayAuth(res.data.msg);
  413. }.bind(this), function (err) {
  414. $h.loadClear();
  415. console.error(err);
  416. });
  417. },
  418. getPlayAuth: function (url) {
  419. var xhr = new XMLHttpRequest();
  420. var that=this;
  421. xhr.onreadystatechange = function () {
  422. if (xhr.readyState == 4 && xhr.status == 200) {
  423. $h.loadClear();
  424. var data = JSON.parse(xhr.responseText);
  425. if (that.taskInfo.type === 2) {
  426. that.audioBar = that.$refs.bar;
  427. that.player = new Aliplayer({
  428. id: 'player',
  429. vid: data.VideoMeta.VideoId,
  430. playauth: data.PlayAuth,
  431. format: 'mp3',
  432. mediaType: 'audio',
  433. encryptType: 1,
  434. autoplay: false
  435. });
  436. that.player.on('ready', function () {
  437. that.audioPlayer.duration = data.VideoMeta.Duration;
  438. }.bind(this));
  439. that.player.on('ended', function () {
  440. that.audioPlayer.paused = true;
  441. }.bind(this));
  442. that.player.on('timeupdate', function () {
  443. that.audioPlayer.currentTime = that.player.getCurrentTime();
  444. that.audioPlayer.range = Math.floor(that.player.getCurrentTime() / that.player.getDuration() * 100);
  445. }.bind(this));
  446. that.player.on('error', function (event) {
  447. console.error(event);
  448. }.bind(this));
  449. } else {
  450. that.player = new Aliplayer({
  451. id: 'player',
  452. vid: data.VideoMeta.VideoId,
  453. playauth: data.PlayAuth,
  454. cover: data.VideoMeta.CoverURL,
  455. encryptType: 1,
  456. autoplay: false,
  457. skinLayout: [
  458. { name: "bigPlayButton", align: "cc" },
  459. {
  460. name: "H5Loading", align: "cc"
  461. },
  462. { name: "errorDisplay", align: "tlabs", x: 0, y: 0 },
  463. { name: "infoDisplay" },
  464. { name: "tooltip", align: "blabs", x: 0, y: 56 },
  465. { name: "thumbnail" },
  466. {
  467. name: "controlBar", align: "blabs", x: 0, y: 0,
  468. children: [
  469. { name: "progress", align: "blabs", x: 0, y: 44 },
  470. { name: "playButton", align: "tl", x: 15, y: 12 },
  471. { name: "timeDisplay", align: "tl", x: 10, y: 7 },
  472. { name: "fullScreenButton", align: "tr", x: 10, y: 12 },
  473. { name: "subtitle", align: "tr", x: 15, y: 12 },
  474. { name: "setting", align: "tr", x: 15, y: 12 },
  475. { name: "volume", align: "tr", x: 5, y: 10 }
  476. ]
  477. }
  478. ]
  479. });
  480. }
  481. } else {
  482. $h.loadClear();
  483. }
  484. }.bind(this);
  485. xhr.open('GET', url);
  486. xhr.send();
  487. }
  488. }
  489. });
  490. });
  491. </script>
  492. {/block}