list.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. <template>
  2. <view class="CoursePage">
  3. <custom-nav title="课程" :to-back="toBack"></custom-nav>
  4. <scroll-view :scroll-y="!detail.vis" class="CourseScrollBody">
  5. <!-- 悬浮窗 -->
  6. <view v-if="!detail.vis && showfu&&img" class="showfu" @click.stop="appectData($event)">
  7. <view class="imgBox">
  8. <image :src="img" mode="widthFix" style="width: 88rpx;height: 88rpx;"></image>
  9. </view>
  10. <image src="../../static/icon/start.png" mode="widthFix" style="width: 40rpx;"></image>
  11. <image src="../../static/icon/xx.png" mode="widthFix" style="width: 40rpx;margin-right: 28rpx;"
  12. @click.stop="clearSave"></image>
  13. </view>
  14. <view class="CourseBody">
  15. <!-- <view style="width: 100rpx;height: 100rpx;" @click="goXia">
  16. 下载1
  17. </view> -->
  18. <view class="CourseHeader">
  19. <picker class="HeaderSeason" mode="selector" :range="title_list" range-key="name"
  20. @change="titlePicker">
  21. <view>
  22. {{title}}
  23. <text></text>
  24. <image src="../../static/icon/triangle.png" mode="widthFix"
  25. style="width: 30rpx;margin-left: 20rpx;"></image>
  26. </view>
  27. </picker>
  28. <!-- <view class="HeaderSeason" @click="mockend">第{{ userServerInfo.season }}届培训课程表</view> -->
  29. <view class="HeaderPlayAll" @click="playAll">
  30. <image v-if="play.ing && play.all" src="../../static/icon/pause1.png" class="PlayIcon" />
  31. <image v-else src="../../static/icon/play1.png" class="PlayIcon">
  32. <view class="PlayText">全部播放</view>
  33. </view>
  34. </view>
  35. <view class="CourseDesc">
  36. 快速精准提高销售能力
  37. </view>
  38. <view class="CourseWeek">
  39. <view v-for="item in weekList" :key="item.id" class="week"
  40. :class="params.week === item.id ? 'active' : ''" @click="params.week = item.id">
  41. {{ item.name }}
  42. </view>
  43. </view>
  44. <view class="CourseList">
  45. <template v-if="courseList.length > 0">
  46. <view v-for="(item, i) in courseList" :key="item.id" class="CourseList-item"
  47. @click="toInfo(item, i)">
  48. <view class="ItemTitle">
  49. <view>
  50. {{ item.course_time | dateFormatter('MM月dd日') }} 周{{ item.course_time | dateWeek }}
  51. </view>
  52. <view class="ItemTitle-status" :class="item.status ? 'active' : ''">
  53. {{ item.status ? '已授课' : '未授课' }}
  54. </view>
  55. </view>
  56. <view class="ItemInfo">
  57. <image :src="item.teacher_img" mode="aspectFill" class="ItemInfo-teamcher">
  58. <view class="Info-right">
  59. <view class="Right-title">{{ item.title }}</view>
  60. <view class="Right-teacher">{{ item.teacher_name }}</view>
  61. <!-- {{ item.teacher_levelname }}: -->
  62. <view class="Right-play" :class="item.status ? '' : 'no_open'">
  63. <template v-if="item.status">
  64. <image v-if="play.ing && play.index === i"
  65. src="../../static/icon/pause2.png" class="Play-icon"
  66. @click.stop="playSelf($event,item, i)" />
  67. <image v-else src="../../static/icon/play2.png" class="Play-icon"
  68. @click.stop="playSelf($event,item, i)" />
  69. </template>
  70. <template v-else>
  71. <image src="../../static/icon/play1.png" class="Play-icon" />
  72. </template>
  73. <view class="Play-Sound">
  74. <view class="SoundWave">
  75. <view v-for="ni in 20" :key="i + '_' + ni" class="Wave-line"
  76. :class="play.ing && play.index === i ? 'active' : ''" />
  77. </view>
  78. </view>
  79. <view class="Play-time">{{ item.course_length | mediaTimeFormatter }}</view>
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. </template>
  85. <template v-else>
  86. <view class="noTip">暂无相关课程</view>
  87. </template>
  88. </view>
  89. </view>
  90. </scroll-view>
  91. <view v-if="detail.vis" class="CourseAudioDetail">
  92. <view class="CoursePlay">
  93. <view class="PlayTitle">{{ detail.info.title }}</view>
  94. <view class="PlayTeacher">{{ detail.info.teacher_name }}</view>
  95. <view class="PlayCover">
  96. <image class="CoverImg" mode="aspectFill" :src="detail.info.teacher_img"
  97. :class="play.ing ? 'start' : 'start paused'" />
  98. </view>
  99. <view class="AudioProgress">
  100. <view class="Progress-left">
  101. <audio-slide class="Audio-slide" :allTime="Number(detail.info.course_length)"
  102. :playTime.sync="play.time" @update:progress="moveAudioPlay" @touchStart="audioTouch" />
  103. </view>
  104. <image v-show="params.season > 33" src="../../static/icon/xia.png" mode="widthFix"
  105. style="width: 60rpx;margin-left: 26rpx;"
  106. @click="goXia(detail.info.title,detail.info.down_link)"></image>
  107. <!-- <view class="Progress-right">倍数</view> -->
  108. </view>
  109. <view class="AudioControl">
  110. <image src="../../static/play/prev_15.png" mode="widthFix" @click="prevTime"></image>
  111. <image src="../../static/play/prev.png" mode="widthFix" @click="toPrev"></image>
  112. <image v-if="!play.ing" src="../../static/play/play.png" mode="widthFix" @click="detailPlay" />
  113. <image v-else src="../../static/play/pause.png" mode="widthFix" @click="detailPlay" />
  114. <image src="../../static/play/next.png" mode="widthFix" @click="toNext"></image>
  115. <image src="../../static/play/next_15.png" mode="widthFix" @click="nextTime"></image>
  116. </view>
  117. </view>
  118. </view>
  119. </view>
  120. </template>
  121. <script>
  122. import {
  123. AudioSlide
  124. } from "../../components/audio-slide.vue"
  125. import {
  126. GetSeason
  127. } from '../../api.js'
  128. import {
  129. mapState
  130. } from "vuex"
  131. export default {
  132. components: {
  133. AudioSlide
  134. },
  135. data() {
  136. return {
  137. typd: 0,
  138. saveData: {},
  139. showfu: false,
  140. title_list: [],
  141. title: '赛季点击此处选择',
  142. params: {
  143. page: 1,
  144. page_size: 15,
  145. week: 1,
  146. season: ''
  147. },
  148. courseList: [],
  149. weekList: [{
  150. id: 0,
  151. name: '课前课'
  152. },
  153. {
  154. id: 1,
  155. name: '第一周'
  156. },
  157. {
  158. id: 2,
  159. name: '第二周'
  160. },
  161. {
  162. id: 3,
  163. name: '第三周'
  164. },
  165. ],
  166. img: '',
  167. play: {
  168. self: null,
  169. index: -1,
  170. all: false,
  171. ing: false,
  172. time: 0,
  173. img: ''
  174. },
  175. detail: {
  176. vis: false,
  177. info: {}
  178. }
  179. }
  180. },
  181. computed: {
  182. ...mapState(['userServerInfo'])
  183. },
  184. watch: {
  185. 'params.week'(a) {
  186. if (this.tyed != 1) {
  187. this.toPause()
  188. this.play.ing = false
  189. this.play.index = -1
  190. this.params.page = 1
  191. this.getCourseList()
  192. console.log(0)
  193. } else {
  194. console.log(1)
  195. this.getCourseList()
  196. this.tyed = 0
  197. }
  198. },
  199. "play.all"(a) {
  200. if (a) {
  201. this.play.self.onEnded(() => {
  202. let len = this.courseList.length - 1
  203. if (this.play.index >= len) {
  204. this.play.index = 0
  205. this.play.all = false
  206. this.play.ing = false
  207. return false
  208. }
  209. let _i = this.play.index + 1
  210. if (!this.courseList[_i].status) {
  211. return false
  212. }
  213. this.toPlay(this.courseList[_i].course_link, this.courseList[_i].title, this.courseList[_i]
  214. .cover_url, () => {
  215. this.play.index = _i
  216. })
  217. if (this.detail.vis) {
  218. this.detail.info = this.courseList[_i]
  219. }
  220. })
  221. } else {
  222. this.play.self ? this.play.self.offEnded() : null
  223. }
  224. },
  225. "play.ing"(a) {
  226. if (a) {
  227. this.play.self.onTimeUpdate(() => {
  228. this.play.time = this.play.self.currentTime
  229. })
  230. this.play.self.onEnded(() => {
  231. if (!this.play.all) {
  232. this.toPause()
  233. this.play.time = 0
  234. }
  235. })
  236. } else {
  237. // this.play.self.offTimeUpdate()
  238. }
  239. },
  240. "detail.info": {
  241. handler(a) {
  242. if (a.course_link) {
  243. this.play.self.onTimeUpdate(() => {
  244. this.play.time = this.play.self.currentTime
  245. })
  246. }
  247. },
  248. deep: true,
  249. immediate: true
  250. }
  251. },
  252. filters: {
  253. dateFormatter: (timestamp, fmt) => {
  254. fmt = fmt || "yyyy-MM-dd";
  255. if (typeof timestamp === 'string') {
  256. timestamp = timestamp.replace(/-/g, '/')
  257. }
  258. const $this = new Date(timestamp);
  259. const o = {
  260. "M+": $this.getMonth() + 1,
  261. "d+": $this.getDate(),
  262. "h+": $this.getHours(),
  263. "m+": $this.getMinutes(),
  264. "s+": $this.getSeconds(),
  265. "q+": Math.floor(($this.getMonth() + 3) / 3),
  266. S: $this.getMilliseconds()
  267. };
  268. if (/(y+)/.test(fmt)) {
  269. fmt = fmt.replace(
  270. RegExp.$1,
  271. ($this.getFullYear() + "").substr(4 - RegExp.$1.length)
  272. );
  273. }
  274. for (var k in o) {
  275. if (new RegExp("(" + k + ")").test(fmt)) {
  276. fmt = fmt.replace(
  277. RegExp.$1,
  278. RegExp.$1.length === 1 ?
  279. o[k] :
  280. ("00" + o[k]).substr(("" + o[k]).length)
  281. );
  282. }
  283. }
  284. return fmt;
  285. },
  286. dateWeek(time) {
  287. if (typeof time === 'string') {
  288. time = time.replace(/-/g, '/')
  289. }
  290. let _d = new Date(time).getDay()
  291. let _a = ['日', '一', '二', '三', '四', '五', '六']
  292. return _a[_d]
  293. },
  294. mediaTimeFormatter: num => {
  295. if (!num) return "00:00";
  296. num = Math.floor(num);
  297. let hour = Math.floor(num / 3600);
  298. let minutes = Math.floor((num - hour * 3600) / 60);
  299. let second = num - hour * 3600 - minutes * 60;
  300. if (hour > 0) {
  301. return `${hour > 9 ? hour : "0" + hour}:${
  302. minutes > 9 ? minutes : "0" + minutes
  303. }:${second > 9 ? second : "0" + second}`;
  304. } else {
  305. return `${minutes > 9 ? minutes : "0" + minutes}:${
  306. second > 9 ? second : "0" + second
  307. }`;
  308. }
  309. }
  310. },
  311. onBackPress() {
  312. return false
  313. },
  314. onShow() {
  315. // 从聊天页面回来
  316. if (this.play.self && this.play.ing) { // 正在播放
  317. this.play.self.seek(this.play.time)
  318. this.play.self.play()
  319. } else if (this.play.self && !this.play.ing) { // 暂停播放,显示悬浮窗
  320. if (uni.getStorageSync('saveData')) {
  321. console.log(121212121)
  322. this.getSave();
  323. // this.showfu = true
  324. // const obj = uni.getStorageSync('saveData')
  325. // this.img = obj.data.teacher_img
  326. }
  327. }
  328. },
  329. onHide() {
  330. // 离开小程序,去聊天
  331. if (this.play.self && !this.play.ing) { // 暂停播放,存储数据
  332. console.log(1121215)
  333. this.saveData.params = this.params
  334. this.saveData.play = this.play
  335. uni.setStorageSync('saveData', this.saveData)
  336. console.log(console.log('存储的saveData', uni.getStorageSync('saveData')))
  337. this.showfu = true
  338. }
  339. },
  340. destroyed() {
  341. // this.toPause()
  342. },
  343. onLoad(e) {
  344. // 从首页进入小程序
  345. this.getSeasonList()
  346. console.log(uni.getStorageSync('saveData'), 'onload中的saveDate')
  347. this.getSave();
  348. if (e.week) {
  349. this.params.week = Number(e.week)
  350. }
  351. },
  352. onUnload() {
  353. console.log('onunload')
  354. // 返回首页,存储数据
  355. if (this.play.index != -1) {
  356. this.saveData.params = this.params
  357. this.saveData.play = this.play
  358. uni.setStorageSync('saveData', this.saveData)
  359. console.log(console.log('跳转页面存储的saveData', uni.getStorageSync('saveData')))
  360. }
  361. },
  362. methods: {
  363. // 获取缓存的数据
  364. getSave() {
  365. if (uni.getStorageSync('saveData')) {
  366. this.showfu = true
  367. const obj = uni.getStorageSync('saveData')
  368. if (obj.play && obj.data) {
  369. const {
  370. index,
  371. ing,
  372. time
  373. } = obj.play
  374. this.play.index = index
  375. this.play.ing = ing
  376. const {
  377. course_link,
  378. cover_url,
  379. title,
  380. teacher_img
  381. } = obj.data
  382. this.play.self.src = course_link
  383. this.play.self.coverImgUrl = cover_url
  384. this.play.self.title = title
  385. this.img = obj.data.teacher_img
  386. }
  387. }
  388. },
  389. //下载音频文件
  390. goXia(title, url) {
  391. let that = this
  392. const filePath = wx.env.USER_DATA_PATH + '/' + title + '.mp4'
  393. const downloadTask = uni.downloadFile({
  394. url: url,
  395. filePath: filePath,
  396. success: (res) => {
  397. if (res.statusCode === 200) {
  398. wx.saveVideoToPhotosAlbum({
  399. filePath: filePath,
  400. success: function(red) {
  401. uni.showToast({
  402. title: '下载成功',
  403. icon: 'none'
  404. })
  405. },
  406. fail: function(err) {
  407. uni.showToast({
  408. title: '下载失败',
  409. icon: 'none'
  410. })
  411. }
  412. })
  413. } else {
  414. uni.showToast({
  415. title: '保存失败',
  416. icon: 'none'
  417. })
  418. }
  419. }
  420. })
  421. downloadTask.onProgressUpdate((res) => {
  422. // console.log('下载进度' + res.progress);
  423. uni.showToast({
  424. title: '下载进度' + res.progress + '%',
  425. icon: 'none'
  426. })
  427. // console.log('已经下载的数据长度' + res.totalBytesWritten);
  428. // console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
  429. })
  430. },
  431. clearSave() {
  432. uni.removeStorageSync('saveData')
  433. this.showfu = false
  434. },
  435. appectData(e) {
  436. const data = uni.getStorageSync('saveData')
  437. if (data.params.week === this.params.week) {
  438. this.tyed = 0
  439. } else {
  440. this.tyed = 1
  441. }
  442. this.params = data.params
  443. this.getSeason(this.params.season)
  444. console.log(this.title_list)
  445. this.play.index = data.play.index
  446. this.play.self.src = data.data.course_link
  447. this.play.time = data.play.time
  448. console.log('play.time', this.play.time)
  449. this.playSelfd(e, data.data, this.play.index) //列表播放
  450. uni.removeStorageSync('saveData')
  451. this.showfu = false
  452. this.toInfo(data.data, this.play.index)
  453. },
  454. // 列表里的暂停播放按钮
  455. playSelfd(e, data, i) {
  456. this.saveData.data = data
  457. uni.removeStorageSync('saveData')
  458. e.stopPropagation()
  459. this.toPlayd(data.course_link, data.title, data.cover_url, () => {
  460. console.log(1, this.play)
  461. this.play.index = i
  462. })
  463. },
  464. toPlayd(src, cb) {
  465. this.play.ing ? this.play.self.pause() : null
  466. this.play.self.src = src;
  467. this.play.self.seek(this.play.time)
  468. this.play.self.play()
  469. this.play.ing = true
  470. cb && cb()
  471. },
  472. getSeason(e) {
  473. // if (e === this.params.season) {
  474. // this.tyed = 0
  475. // } else {
  476. // this.tyed = 1
  477. // }
  478. let i = this.title_list.findIndex(item => item.season == e)
  479. this.title = this.title_list[i].name
  480. this.season = this.title_list[i].season
  481. this.getCourseList()
  482. },
  483. getSeasonList() {
  484. this.$ajax.get(`${GetSeason}`).then(([, {
  485. data: res
  486. }]) => {
  487. if (res.code === 200) {
  488. var arr = res.data
  489. arr.forEach((item, i) => {
  490. item.name = '第' + item.season + '届培训课程表'
  491. })
  492. this.title_list = arr
  493. this.title = this.title_list[0].name
  494. this.season = res.data[0].season
  495. uni.hideLoading()
  496. this.getCourseList()
  497. this.init()
  498. }
  499. })
  500. },
  501. titlePicker(e) {
  502. console.log(e.target.value)
  503. this.title = this.title_list[e.target.value].name
  504. this.season = this.title_list[e.target.value].season
  505. this.toPause()
  506. this.play.ing = false
  507. this.play.index = -1
  508. this.params.page = 1
  509. this.getCourseList()
  510. },
  511. audioTouch() {
  512. this.toPause()
  513. },
  514. mockend() {
  515. this.play.self.seek(212)
  516. },
  517. toBack() {
  518. if (this.detail.vis) {
  519. this.detail.time = 0
  520. this.detail.info = {}
  521. this.detail.vis = false
  522. if (!this.play.ing) { //暂停状态返回列表,显示悬浮窗
  523. this.saveData.params = this.params
  524. this.saveData.play = this.play
  525. uni.setStorageSync('saveData', this.saveData)
  526. this.img = this.saveData.data.teacher_img
  527. console.log(console.log('11存储的saveData1', uni.getStorageSync('saveData')))
  528. this.showfu = true
  529. }
  530. } else {
  531. // console.log(111,this.play.self)
  532. // uni.setStorageSync('floating', this.play)
  533. uni.navigateBack()
  534. }
  535. },
  536. init() {
  537. // this.play.self = uni.createInnerAudioContext()
  538. this.play.self = uni.getBackgroundAudioManager()
  539. },
  540. toPlay(src, title, cover_rul, cb) {
  541. this.play.ing ? this.play.self.pause() : null
  542. this.play.self = uni.getBackgroundAudioManager();
  543. this.play.self.title = title;
  544. this.play.self.coverImgUrl = cover_rul;
  545. this.play.self.src = encodeURI(src)
  546. this.play.ing = true
  547. wx.setInnerAudioOption({
  548. obeyMuteSwitch: false,
  549. success: function(e) {
  550. console.log('play success')
  551. },
  552. fail: function(e) {
  553. console.log(e)
  554. console.log('play fail')
  555. }
  556. })
  557. cb && cb()
  558. },
  559. toPause() {
  560. if (!this.play.ing) {
  561. return false
  562. }
  563. this.play.ing = false
  564. this.play.self.pause()
  565. },
  566. playAll() {
  567. if (this.courseList.length === 0) {
  568. uni.showModal({
  569. content: "没有可播放的课程",
  570. showCancel: false
  571. })
  572. return false
  573. }
  574. let _this = this
  575. if (this.play.ing) {
  576. if (this.play.all) {
  577. this.toPause()
  578. } else {
  579. if (this.play.index === -1) {
  580. this.toPause()
  581. } else {
  582. this.play.all = true
  583. }
  584. }
  585. return false
  586. }
  587. if (this.play.index === -1) {
  588. this.toPlay(this.courseList[0].course_link, this.courseList[0].title, this.courseList[0].cover_url,
  589. () => {
  590. this.play.all = true
  591. this.play.index = 0
  592. })
  593. } else {
  594. this.play.ing = true;
  595. this.play.self.play()
  596. }
  597. },
  598. // 列表里的暂停播放按钮
  599. playSelf(e, data, i) {
  600. this.saveData.data = data
  601. uni.removeStorageSync('saveData')
  602. this.showfu = false
  603. e.stopPropagation()
  604. if (!data.status) {
  605. uni.showModal({
  606. content: '课程还未开始, 暂不能播放',
  607. showCancel: false
  608. })
  609. return false
  610. }
  611. if (this.play.ing && this.play.index === i) {
  612. this.toPause()
  613. return false
  614. }
  615. this.toPlay(data.course_link, data.title, data.cover_url, () => {
  616. console.log(1, this.play)
  617. this.play.index = i
  618. })
  619. },
  620. getCourseList() {
  621. this.params.season = this.season
  622. let {
  623. page,
  624. page_size,
  625. week,
  626. season
  627. } = this.params
  628. let params = []
  629. Object.keys(this.params).forEach(k => {
  630. params.push(`${k}=${this.params[k]}`)
  631. })
  632. let _s = params.join('&')
  633. this.$ajax.get(`/course/course_list?${_s}`).then(([, {
  634. data: res
  635. }]) => {
  636. if (res.code === 200) {
  637. this.courseList = res.data.list
  638. this.$store.commit('CHANGECOURSELIST', res.data.list)
  639. }
  640. })
  641. },
  642. toPrev() {
  643. if (this.play.index === 0) {
  644. uni.showModal({
  645. content: "前面没有课程了",
  646. showCancel: false
  647. })
  648. return false
  649. }
  650. let _i = this.play.index - 1
  651. if (!this.courseList[_i].status) {
  652. uni.showModal({
  653. content: "上一个课程还未开始",
  654. showCancel: false
  655. })
  656. return false
  657. }
  658. this.play.time = 0
  659. this.toPlay(this.courseList[_i].course_link, this.courseList[_i].title, this.courseList[_i].cover_url,
  660. () => {
  661. this.play.index = _i
  662. })
  663. this.detail.info = Object.assign({}, this.courseList[_i])
  664. },
  665. toNext() {
  666. let max = this.courseList.length - 1
  667. if (this.play.index >= max) {
  668. uni.showModal({
  669. content: "后面没有课程了",
  670. showCancel: false
  671. })
  672. return false
  673. }
  674. let _i = this.play.index + 1
  675. if (!this.courseList[_i].status) {
  676. uni.showModal({
  677. content: "下一个课程还未开始",
  678. showCancel: false
  679. })
  680. return false
  681. }
  682. this.play.time = 0
  683. this.toPlay(this.courseList[_i].course_link, this.courseList[_i].title, this.courseList[_i].cover_url,
  684. () => {
  685. this.play.index = _i
  686. })
  687. this.detail.info = Object.assign({}, this.courseList[_i])
  688. },
  689. toInfo(data, i) {
  690. uni.removeStorageSync('saveData')
  691. console.log(uni.getStorageInfo('saveData'), '点击详情的save')
  692. console.log(data, 'data')
  693. this.saveData.data = data
  694. this.showfu = false
  695. if (!data.status) {
  696. uni.showModal({
  697. content: '课程还未开始',
  698. showCancel: false
  699. })
  700. return false
  701. }
  702. if (i !== this.play.index) {
  703. // this.play.self.src = data.course_link
  704. this.play.ing ? this.toPause() : null
  705. this.play.index = i
  706. this.play.time = 0
  707. this.play.self.seek(this.play.time)
  708. }
  709. this.detail.info = data
  710. this.detail.vis = true
  711. },
  712. moveAudioPlay({
  713. value
  714. }) {
  715. this.play.time = value
  716. this.play.self.seek(value)
  717. this.toPlay()
  718. },
  719. // 倒退15秒
  720. prevTime() {
  721. this.play.time = this.play.time > 15 ? this.play.time - 15 : 0
  722. this.play.self.seek(this.play.time)
  723. },
  724. // 快进15秒
  725. nextTime() {
  726. let max = Number(this.detail.info.course_length)
  727. this.play.time = this.play.time < max ? this.play.time + 15 : max
  728. this.play.self.seek(this.play.time)
  729. },
  730. // 播放详情里的 播放和暂停
  731. detailPlay() {
  732. if (this.play.ing) { // 暂停
  733. this.toPause()
  734. } else { // 播放
  735. const {
  736. title,
  737. cover_rul,
  738. course_link
  739. } = this.detail.info
  740. this.play.self = uni.getBackgroundAudioManager();
  741. this.play.self.title = title;
  742. this.play.self.coverImgUrl = cover_rul;
  743. this.play.self.src = course_link
  744. // this.play.self.play();
  745. this.play.ing = true;
  746. wx.setInnerAudioOption({
  747. obeyMuteSwitch: false,
  748. success: function(e) {
  749. console.log(e)
  750. console.log('play success')
  751. },
  752. fail: function(e) {
  753. console.log(e)
  754. console.log('play fail')
  755. }
  756. })
  757. }
  758. }
  759. }
  760. }
  761. </script>
  762. <style lang="scss">
  763. .showfu {
  764. width: 268rpx;
  765. height: 96rpx;
  766. background: #5B5B5B;
  767. box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.16);
  768. border-radius: 50rpx;
  769. position: fixed;
  770. right: 44rpx;
  771. bottom: 80rpx;
  772. display: flex;
  773. justify-content: space-between;
  774. align-items: center;
  775. .imgBox {
  776. width: 96rpx;
  777. height: 96rpx;
  778. border: 6rpx solid #FFFFFF;
  779. border-radius: 50%;
  780. overflow: hidden;
  781. }
  782. }
  783. .select {
  784. margin-top: 20rpx;
  785. padding-left: 30rpx;
  786. font-size: 34rpx;
  787. }
  788. .noTip {
  789. padding: 20rpx;
  790. text-align: center;
  791. width: 100%;
  792. color: #999999;
  793. }
  794. $rotate: 0deg;
  795. .CoursePage {
  796. @include page();
  797. display: flex;
  798. flex-direction: column;
  799. justify-content: space-between;
  800. .CourseAudioDetail {
  801. @include page();
  802. position: fixed;
  803. height: 100%;
  804. bottom: 0;
  805. left: 0;
  806. right: 0;
  807. background-color: #FFFFFF;
  808. overflow: hidden;
  809. .CoursePlay {
  810. padding: 30rpx;
  811. width: 100%;
  812. box-sizing: border-box;
  813. display: flex;
  814. align-items: center;
  815. justify-content: flex-start;
  816. flex-direction: column;
  817. .PlayTitle {
  818. width: 100%;
  819. color: #333333;
  820. font-size: 40rpx;
  821. line-height: 60rpx;
  822. text-align: center;
  823. margin-bottom: 40rpx;
  824. }
  825. .PlayTeacher {
  826. color: #999999;
  827. font-size: 32rpx;
  828. line-height: 60rpx;
  829. text-align: center;
  830. margin-bottom: 40rpx;
  831. }
  832. .PlayCover {
  833. width: 496rpx;
  834. height: 496rpx;
  835. border-radius: 50%;
  836. background-color: #333333;
  837. padding: 26rpx;
  838. box-sizing: border-box;
  839. .CoverImg {
  840. display: block;
  841. width: 100%;
  842. height: 100%;
  843. border-radius: 50%;
  844. &.start {
  845. animation: rotate 10s 0s infinite linear;
  846. }
  847. &.paused {
  848. animation-play-state: paused;
  849. }
  850. }
  851. margin-bottom: 150rpx;
  852. }
  853. .AudioProgress {
  854. width: 100%;
  855. display: flex;
  856. align-items: center;
  857. justify-content: space-between;
  858. margin-bottom: 50rpx;
  859. .Progress-right {
  860. color: #EA4A41;
  861. font-size: 24rpx;
  862. margin-left: 30px;
  863. }
  864. .Progress-left {
  865. flex: 1;
  866. min-width: 0;
  867. .Audio-slide {
  868. margin: 0;
  869. }
  870. }
  871. }
  872. .AudioControl {
  873. display: flex;
  874. align-items: center;
  875. justify-content: space-between;
  876. width: 100%;
  877. image {
  878. &:nth-of-type(1),
  879. &:nth-last-of-type(1) {
  880. width: 43rpx;
  881. height: 38rpx;
  882. }
  883. &:nth-of-type(2),
  884. &:nth-last-of-type(2) {
  885. width: 38rpx;
  886. height: 46rpx;
  887. }
  888. &:nth-of-type(3) {
  889. width: 124rpx;
  890. height: 124rpx;
  891. }
  892. }
  893. }
  894. }
  895. }
  896. .CourseScrollBody {
  897. width: 100%;
  898. flex: 1;
  899. overflow: hidden;
  900. position: relative;
  901. }
  902. }
  903. .CourseBody {
  904. width: 100%;
  905. padding: 30rpx;
  906. box-sizing: border-box;
  907. .CourseHeader {
  908. width: 100%;
  909. display: flex;
  910. align-items: center;
  911. justify-content: space-between;
  912. margin-bottom: 22rpx;
  913. .HeaderSeason {
  914. flex: 1;
  915. overflow: hidden;
  916. text-overflow: hidden;
  917. color: #333333;
  918. font-size: 44rpx;
  919. margin-right: 20rpx;
  920. }
  921. .HeaderPlayAll {
  922. width: 208rpx;
  923. height: 68rpx;
  924. background-color: #F8F8F8;
  925. display: flex;
  926. align-items: center;
  927. justify-content: center;
  928. border-radius: 8rpx;
  929. .PlayIcon {
  930. width: 36rpx;
  931. height: 36rpx;
  932. }
  933. .PlayText {
  934. font-size: 28rpx;
  935. color: #999999;
  936. margin-left: 16rpx;
  937. line-height: 40rpx;
  938. }
  939. }
  940. }
  941. .CourseDesc {
  942. color: #999999;
  943. font-size: 28rpx;
  944. line-height: 40rpx;
  945. margin-bottom: 32rpx;
  946. }
  947. .CourseWeek {
  948. width: 100%;
  949. display: flex;
  950. align-items: center;
  951. justify-content: space-between;
  952. margin-bottom: 60rpx;
  953. .week {
  954. // width: 192rpx;
  955. padding: 0 30rpx;
  956. height: 68rpx;
  957. border-radius: 68rpx;
  958. text-align: center;
  959. line-height: 68rpx;
  960. background: #F8F8F8;
  961. color: #999999;
  962. font-size: 28rpx;
  963. &.active {
  964. color: #FFFFFF !important;
  965. background: linear-gradient(to right, #F97C55, #F44545) !important;
  966. }
  967. }
  968. }
  969. .CourseList {
  970. &-item {
  971. margin-bottom: 40rpx;
  972. &:nth-last-of-type(1) {
  973. margin-bottom: 0;
  974. }
  975. .ItemTitle {
  976. color: #333333;
  977. font-size: 32rpx;
  978. line-height: 44rpx;
  979. margin-bottom: 30rpx;
  980. display: flex;
  981. align-items: center;
  982. justify-content: space-between;
  983. &-status {
  984. height: 44rpx;
  985. line-height: 44rpx;
  986. width: 118rpx;
  987. border: 2rpx solid #999999;
  988. color: #999999;
  989. text-align: center;
  990. font-size: 28rpx;
  991. box-sizing: border-box;
  992. &.active {
  993. border-color: #EA4A41 !important;
  994. color: #EA4A41 !important;
  995. }
  996. }
  997. }
  998. .ItemInfo {
  999. width: 100%;
  1000. display: flex;
  1001. align-items: stretch;
  1002. justify-content: space-between;
  1003. .ItemInfo-teamcher {
  1004. display: block;
  1005. width: 180rpx;
  1006. height: 234rpx;
  1007. }
  1008. .Info-right {
  1009. flex: 1;
  1010. overflow: hidden;
  1011. margin-left: 16rpx;
  1012. display: flex;
  1013. justify-content: space-between;
  1014. flex-direction: column;
  1015. align-items: flex-start;
  1016. .Right-title {
  1017. color: #333333;
  1018. font-size: 32rpx;
  1019. line-height: 44rpx;
  1020. }
  1021. .Right-teacher {
  1022. color: #999999;
  1023. font-size: 28rpx;
  1024. line-height: 40rpx;
  1025. }
  1026. .Right-play {
  1027. width: 422rpx;
  1028. height: 60rpx;
  1029. padding: 12rpx 14rpx;
  1030. box-sizing: border-box;
  1031. display: flex;
  1032. align-items: center;
  1033. background: linear-gradient(to right, #F97C55, #F44545);
  1034. border-radius: 60rpx;
  1035. margin-bottom: 22rpx;
  1036. display: flex;
  1037. align-items: center;
  1038. justify-content: space-between;
  1039. &.no_open {
  1040. background: #F8F8F8 !important;
  1041. .Play-time {
  1042. color: #999999 !important;
  1043. }
  1044. /deep/ .Wave-line {
  1045. background: #999999 !important;
  1046. }
  1047. }
  1048. .Play-icon {
  1049. display: block;
  1050. width: 36rpx;
  1051. height: 36rpx;
  1052. }
  1053. .Play-time {
  1054. color: #FFFFFF;
  1055. font-size: 28rpx;
  1056. }
  1057. .Play-Sound {
  1058. flex: 1;
  1059. height: 100%;
  1060. overflow: hidden;
  1061. margin: 0 20rpx;
  1062. }
  1063. }
  1064. }
  1065. }
  1066. }
  1067. }
  1068. }
  1069. .SoundWave {
  1070. width: 100%;
  1071. height: 100%;
  1072. display: flex;
  1073. align-items: center;
  1074. justify-content: space-between;
  1075. .Wave-line {
  1076. width: 4rpx;
  1077. background: #FFFFFF;
  1078. border-radius: 4rpx;
  1079. @for $i from 1 through 20 {
  1080. &:nth-of-type(#{$i}) {
  1081. height: #{random(40)}rpx;
  1082. }
  1083. }
  1084. &.active {
  1085. @for $i from 1 through 20 {
  1086. &:nth-of-type(#{$i}) {
  1087. animation: load 2.5s #{(random(10)*0.2)+ 1}s infinite linear;
  1088. }
  1089. }
  1090. }
  1091. }
  1092. }
  1093. @keyframes load {
  1094. 0% {
  1095. height: 100%;
  1096. }
  1097. 30% {
  1098. height: 20%;
  1099. }
  1100. 60% {
  1101. height: 60%;
  1102. }
  1103. 100% {
  1104. height: 10%;
  1105. }
  1106. }
  1107. @keyframes rotate {
  1108. 100% {
  1109. transform: rotate(360deg);
  1110. }
  1111. }
  1112. </style>