与牧同行-小程序用户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
8.4 KiB

  1. // pages/training/videoDetail/videoDetail.js
  2. import http from '../../../utils/api'
  3. const baseUrl = require('../../../utils/baseUrl')
  4. Page({
  5. data: {
  6. baseUrl: baseUrl,
  7. video: {},
  8. videoUrl: '',
  9. loading: true,
  10. fullScreen: false,
  11. isPlaying: false,
  12. isMuted: false,
  13. loop: false,
  14. playbackRate: 1,
  15. currentTime: 0,
  16. duration: 0,
  17. videoTags: [],
  18. videoError: false,
  19. autoplay: false,
  20. controlsVisible: true,
  21. controlsTimer: null,
  22. lastTouchTime: 0,
  23. },
  24. onLoad(options) {
  25. console.log('页面参数:', options)
  26. this.getVideoDetails(options.id)
  27. },
  28. onReady() {
  29. this.videoContext = wx.createVideoContext('videoPlayer', this)
  30. console.log('视频上下文创建成功')
  31. },
  32. onUnload() {
  33. // 清除定时器
  34. if (this.data.controlsTimer) {
  35. clearTimeout(this.data.controlsTimer)
  36. }
  37. // 页面卸载时停止播放
  38. if (this.videoContext) {
  39. this.videoContext.pause()
  40. }
  41. },
  42. // 获取视频详情
  43. getVideoDetails(id) {
  44. this.setData({
  45. loading: true,
  46. videoError: false
  47. })
  48. http.videoDetails({
  49. data: { id },
  50. success: res => {
  51. console.log('视频详情响应:', res)
  52. if (res.code === 200 && res.data) {
  53. const video = res.data
  54. console.log('视频数据:', video)
  55. // 处理视频URL
  56. let videoUrl = ''
  57. if (video.videoUrl) {
  58. videoUrl = this.data.baseUrl + video.videoUrl
  59. console.log('视频完整URL:', videoUrl)
  60. }
  61. // 处理视频标签
  62. const tags = video.tags ? video.tags.split(',').filter(tag => tag.trim()) : []
  63. this.setData({
  64. video: video,
  65. videoUrl: videoUrl,
  66. videoTags: tags,
  67. loading: false
  68. })
  69. // 设置页面标题
  70. wx.setNavigationBarTitle({
  71. title: video.title.substring(0, 12) + (video.title.length > 12 ? '...' : '')
  72. })
  73. } else {
  74. wx.showToast({
  75. title: res.msg || '视频不存在',
  76. icon: 'none',
  77. duration: 2000
  78. })
  79. setTimeout(() => {
  80. wx.navigateBack()
  81. }, 2000)
  82. }
  83. },
  84. fail: err => {
  85. console.error('获取视频详情失败:', err)
  86. this.setData({
  87. loading: false,
  88. videoError: true
  89. })
  90. wx.showToast({
  91. title: '加载失败,请重试',
  92. icon: 'none',
  93. duration: 2000
  94. })
  95. }
  96. })
  97. },
  98. // 返回上一页
  99. goBack() {
  100. wx.navigateBack()
  101. },
  102. // 视频加载完成
  103. onVideoLoaded(e) {
  104. console.log('视频元数据加载完成:', e.detail)
  105. this.setData({
  106. duration: e.detail.duration || 0,
  107. videoError: false
  108. })
  109. },
  110. // 视频播放错误
  111. onVideoError(e) {
  112. console.error('视频播放错误详情:', e.detail)
  113. this.setData({
  114. videoError: true,
  115. isPlaying: false
  116. })
  117. wx.showModal({
  118. title: '播放错误',
  119. content: '视频加载失败,请检查网络或视频链接',
  120. showCancel: true,
  121. confirmText: '重试',
  122. success: (res) => {
  123. if (res.confirm) {
  124. this.retryVideo()
  125. }
  126. }
  127. })
  128. },
  129. // 视频播放事件
  130. onVideoPlay(e) {
  131. console.log('视频开始播放')
  132. this.setData({
  133. isPlaying: true,
  134. videoError: false
  135. })
  136. // 播放时隐藏控制栏
  137. if (this.data.fullScreen) {
  138. this.hideControls()
  139. }
  140. },
  141. // 视频暂停事件
  142. onVideoPause(e) {
  143. console.log('视频暂停')
  144. this.setData({
  145. isPlaying: false
  146. })
  147. // 暂停时显示控制栏
  148. if (this.data.fullScreen) {
  149. this.showControls()
  150. }
  151. },
  152. // 视频播放结束
  153. onVideoEnded(e) {
  154. console.log('视频播放结束')
  155. this.setData({
  156. isPlaying: false,
  157. currentTime: 0
  158. })
  159. // 结束播放时显示控制栏
  160. if (this.data.fullScreen) {
  161. this.showControls()
  162. }
  163. },
  164. // 时间更新事件
  165. onTimeUpdate(e) {
  166. const currentTime = e.detail.currentTime
  167. const duration = e.detail.duration
  168. // 更新当前时间和总时长
  169. this.setData({
  170. currentTime: currentTime,
  171. duration: duration > 0 ? duration : this.data.duration
  172. })
  173. },
  174. // 全屏切换事件
  175. onFullScreenChange(e) {
  176. const fullScreen = e.detail.fullScreen
  177. console.log('全屏状态变化:', fullScreen)
  178. this.setData({
  179. fullScreen: fullScreen,
  180. controlsVisible: !fullScreen
  181. })
  182. if (fullScreen) {
  183. wx.setKeepScreenOn({ keepScreenOn: true })
  184. // 进入全屏后自动播放
  185. setTimeout(() => {
  186. this.videoContext.play()
  187. }, 300)
  188. } else {
  189. wx.setKeepScreenOn({ keepScreenOn: false })
  190. // 退出全屏时暂停
  191. this.videoContext.pause()
  192. }
  193. },
  194. // 进入全屏
  195. enterFullScreen() {
  196. this.videoContext.requestFullScreen({ direction: 90 })
  197. },
  198. // 退出全屏
  199. exitFullScreen() {
  200. this.videoContext.exitFullScreen()
  201. },
  202. // 切换播放状态
  203. togglePlay() {
  204. console.log('切换播放状态,当前状态:', this.data.isPlaying)
  205. if (this.data.videoError) {
  206. this.retryVideo()
  207. return
  208. }
  209. if (this.data.isPlaying) {
  210. this.videoContext.pause()
  211. } else {
  212. this.videoContext.play()
  213. }
  214. },
  215. // 切换静音
  216. toggleMute() {
  217. const isMuted = !this.data.isMuted
  218. this.setData({ isMuted: isMuted })
  219. this.videoContext.muted(isMuted)
  220. wx.showToast({
  221. title: isMuted ? '已静音' : '已取消静音',
  222. icon: 'none',
  223. duration: 800
  224. })
  225. },
  226. // 切换循环
  227. toggleLoop() {
  228. const loop = !this.data.loop
  229. this.setData({ loop: loop })
  230. this.videoContext.loop(loop)
  231. wx.showToast({
  232. title: loop ? '开启循环播放' : '关闭循环播放',
  233. icon: 'none',
  234. duration: 800
  235. })
  236. },
  237. // 切换播放速度
  238. toggleSpeed() {
  239. const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2]
  240. const currentIndex = speeds.indexOf(this.data.playbackRate)
  241. const nextIndex = (currentIndex + 1) % speeds.length
  242. const nextSpeed = speeds[nextIndex]
  243. this.setData({ playbackRate: nextSpeed })
  244. this.videoContext.playbackRate(nextSpeed)
  245. wx.showToast({
  246. title: `播放速度 ${nextSpeed}x`,
  247. icon: 'none',
  248. duration: 800
  249. })
  250. },
  251. // 重试播放
  252. retryVideo() {
  253. console.log('重试播放视频')
  254. this.setData({
  255. videoError: false,
  256. loading: true
  257. })
  258. // 重新加载视频
  259. setTimeout(() => {
  260. this.setData({ loading: false })
  261. if (this.videoContext) {
  262. this.videoContext.seek(0)
  263. this.videoContext.play()
  264. }
  265. }, 500)
  266. },
  267. // 触摸控制
  268. onTouchControl(e) {
  269. const type = e.currentTarget.dataset.type
  270. const currentTime = this.data.currentTime
  271. const duration = this.data.duration
  272. if (type === 'backward') {
  273. const newTime = Math.max(0, currentTime - 10)
  274. this.setData({ currentTime: newTime })
  275. this.videoContext.seek(newTime)
  276. wx.showToast({
  277. title: '-10秒',
  278. icon: 'none',
  279. duration: 500
  280. })
  281. } else if (type === 'forward') {
  282. const newTime = Math.min(duration, currentTime + 10)
  283. this.setData({ currentTime: newTime })
  284. this.videoContext.seek(newTime)
  285. wx.showToast({
  286. title: '+10秒',
  287. icon: 'none',
  288. duration: 500
  289. })
  290. }
  291. },
  292. // 触摸移动
  293. onTouchMove() {
  294. if (this.data.fullScreen) {
  295. this.showControls()
  296. this.hideControls()
  297. }
  298. },
  299. // 显示控制栏
  300. showControls() {
  301. this.setData({ controlsVisible: true })
  302. // 清除之前的定时器
  303. if (this.data.controlsTimer) {
  304. clearTimeout(this.data.controlsTimer)
  305. }
  306. // 3秒后自动隐藏控制栏
  307. const timer = setTimeout(() => {
  308. if (this.data.isPlaying && this.data.fullScreen) {
  309. this.setData({ controlsVisible: false })
  310. }
  311. }, 3000)
  312. this.setData({ controlsTimer: timer })
  313. },
  314. // 隐藏控制栏
  315. hideControls() {
  316. if (this.data.controlsTimer) {
  317. clearTimeout(this.data.controlsTimer)
  318. }
  319. const timer = setTimeout(() => {
  320. if (this.data.isPlaying && this.data.fullScreen) {
  321. this.setData({ controlsVisible: false })
  322. }
  323. }, 3000)
  324. this.setData({ controlsTimer: timer })
  325. },
  326. })