onlineTrainingDetails.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <template>
  2. <view class="details">
  3. <!-- 视频 -->
  4. <view class="details-video" v-if="isPaly">
  5. <video class="details-video-con" id="myVideo" @timeupdate="timeUpdate" :src="videoInfo.videoUrl" controls
  6. :initial-time="initial_time" object-fit="fill" play-btn-position="center" @tap="videoClick">
  7. <cover-view class="video-control">
  8. <cover-view class="multi rate" @tap.stop="showSwitchRate">x {{ currentRate }}</cover-view>
  9. </cover-view>
  10. <cover-view class="multi-list rate" :class="{ active: rateShow }">
  11. <cover-view v-for="(item, index) in ['0.5', '1.0', '1.5', '2.0']" :key="index"
  12. class="multi-item rate" :data-rate="item" @tap="switchRate"
  13. :class="{ active: item == currentRate }">
  14. {{ item }}
  15. </cover-view>
  16. </cover-view>
  17. </video>
  18. </view>
  19. <!-- 介绍 -->
  20. <view class="details-content">
  21. <view class="details-content-title">{{ videoInfo.chapterName }}</view>
  22. <view class="details-content-progress">本课程
  23. 共{{ info.amount }}课,已学完{{ info.finishCount }}课,共进度{{ info.finishPercent || 0 }}%</view>
  24. <view class="details-content-teacher">主讲老师:{{ info.presenter }}</view>
  25. <view class="details-content-info">{{ videoInfo.chapterInfo }}</view>
  26. </view>
  27. <!-- 课程章节 -->
  28. <view class="details-classes">
  29. <view class="details-classes-header">
  30. <view>精选课程</view>
  31. <view>更多
  32. <u-icon name="arrow-right" size="22" color="#A3A3A3" />
  33. </view>
  34. </view>
  35. <view class="details-classes-list">
  36. <view class="details-classes-list-item" v-for="(item, index) in info.chapterList" :key="index"
  37. :class="{'active': index === videoIndex }" @click="classesClick(index)">
  38. <view>{{ index + 1 }}</view>
  39. <view>{{ item.flag === 2 ? '已学' : (item.finishPercent + '%') }}</view>
  40. </view>
  41. </view>
  42. </view>
  43. <view class="details-line">
  44. <view></view>
  45. </view>
  46. <!-- 评论 -->
  47. <view class="details-comment">
  48. <view class="details-comment-header">
  49. <view>课程评论</view>
  50. <view>共{{ total }}条评论</view>
  51. </view>
  52. <view class="details-comment-list">
  53. <view class="details-comment-list-item" v-for="(item, index) in commentList" :key="index">
  54. <view class="left">
  55. <u-avatar :src="item.createByAvatar" size="96" mode="square"></u-avatar>
  56. </view>
  57. <view class="right">
  58. <view>{{ item.createBy }}</view>
  59. <view>
  60. <u-rate :count="5" size="24" disabled="" active-color="#C4C4C4" v-model="item.starLevel">
  61. </u-rate>
  62. <text>{{ item.createTime }}</text>
  63. </view>
  64. <view>{{ item.content }}</view>
  65. </view>
  66. </view>
  67. </view>
  68. <view class="details-comment-page" v-if="total">
  69. <wyb-pagination :padding="0" :totalItems="total" :current="query.pageNum" @change="pageChange" />
  70. </view>
  71. <view class="details-comment-mine">
  72. <text>我的评论</text>
  73. </view>
  74. <view class="details-comment-conent">
  75. <view class="details-comment-conent-star">
  76. <u-rate :count="5" size="40" active-color="#FFBC00" v-model="form.starLevel"></u-rate>
  77. </view>
  78. <view class="details-comment-content-textarea">
  79. <u-input v-model="form.content" placeholder="请输入您的评价" type="textarea"
  80. :custom-style="{ backgroundColor: '#F5F5F5', padding: '30rpx', borderRadius: '10rpx', minHeight: '280rpx' }">
  81. </u-input>
  82. </view>
  83. <view class="details-comment-conent-button" @click="submitCommet">提交</view>
  84. </view>
  85. </view>
  86. <u-toast ref="uToast" />
  87. </view>
  88. </template>
  89. <script>
  90. import wybPagination from '@/components/wyb-pagination/wyb-pagination.vue'
  91. export default {
  92. data() {
  93. return {
  94. info: {},
  95. videoContext: uni.createVideoContext('myVideo', this),
  96. videoInfo: {},
  97. videoIndex: 0,
  98. // 视频实时时间
  99. initial_time: 0,
  100. // 视频已经播放时间
  101. playedTime: 0,
  102. rateShow: false, // 倍速浮层
  103. currentRate: 1.0, // 默认倍速
  104. // 视频实际时间
  105. video_real_time: 0,
  106. classesId: '',
  107. isPaly: true,
  108. query: {
  109. pageNum: 1,
  110. pageSize: 5,
  111. tabId: ''
  112. },
  113. total: 0,
  114. commentList: [],
  115. form: {
  116. tabId: '',
  117. starLevel: 0,
  118. content: ''
  119. }
  120. }
  121. },
  122. onLoad(page) {
  123. if (page.id) {
  124. this.getClassesDetails(page.id);
  125. this.classesId = page.id
  126. }
  127. },
  128. beforeDestroy() {
  129. this.submitTimeLong({
  130. tabId: this.videoInfo.id,
  131. playDuration: this.video_real_time
  132. }, 0, true)
  133. },
  134. methods: {
  135. /**
  136. * 显示倍速浮层
  137. * @param {Object} rate
  138. */
  139. showSwitchRate(rate) {
  140. let that = this;
  141. that.rateShow = true;
  142. },
  143. /**
  144. * 切换倍速
  145. * @param {Object} e
  146. */
  147. switchRate(e) {
  148. let that = this;
  149. let rate = Number(e.currentTarget.dataset.rate);
  150. that.currentRate = rate;
  151. that.rateShow = false;
  152. this.videoContext.playbackRate(rate);
  153. },
  154. /**
  155. * 视频点击
  156. * @param {Object} e
  157. */
  158. videoClick(e) {
  159. this.rateShow = false;
  160. },
  161. /**
  162. * 获取课程详情
  163. * @param {Object} id
  164. */
  165. getClassesDetails(id) {
  166. this.$u.api.training.getOnlineDetailsApi({
  167. id
  168. }).then(res => {
  169. if (res.code === 200) {
  170. this.info = res.data;
  171. this.videoInfo = res.data.chapterList[this.videoIndex];
  172. this.initial_time = Number(res.data.chapterList[this.videoIndex].playDuration)
  173. this.video_real_time = Number(res.data.chapterList[this.videoIndex].playDuration)
  174. this.playedTime = Number(res.data.chapterList[this.videoIndex].playDuration)
  175. this.query.tabId = res.data.chapterList[this.videoIndex].id
  176. this.form.tabId = res.data.chapterList[this.videoIndex].id
  177. this.query.pageNum = res.data.page;
  178. this.isPaly = true
  179. this.getCommentList();
  180. }
  181. })
  182. },
  183. /**
  184. * 课程章节点击
  185. * @param {Object} index
  186. */
  187. classesClick(index) {
  188. this.isPaly = false
  189. this.submitTimeLong ({
  190. tabId: this.videoInfo.id,
  191. playDuration: this.video_real_time
  192. }, index);
  193. },
  194. /**
  195. * 控制视频不能快进
  196. * @param {Object} e
  197. */
  198. timeUpdate(e) {
  199. let isReady = 1; // 是否开启可以视频快进 1 禁止开启
  200. if (this.videoInfo.finishPercent === 100) {
  201. isReady = 3;
  202. }
  203. //跳转到指定播放位置 initial-time 时间为秒
  204. let that = this;
  205. //播放的总时长
  206. let duration = e.detail.duration
  207. //实时播放进度 秒数
  208. let currentTime = parseInt(e.detail.currentTime)
  209. //当前视频进度
  210. let jump_time = 0
  211. if (that.video_real_time == 0) {
  212. jump_time = parseInt(that.initial_time) + parseInt(that.video_real_time)
  213. } else {
  214. jump_time = parseInt(that.video_real_time)
  215. }
  216. if (jump_time === currentTime) {
  217. isReady = 3;
  218. }
  219. if(isReady === 1){
  220. if (currentTime > jump_time && currentTime - jump_time > 3) {
  221. let videoContext = wx.createVideoContext('myVideo')
  222. videoContext.seek(that.video_real_time)
  223. wx.showToast({
  224. title: '未完整看完该视频,不能快进',
  225. icon: 'none',
  226. duration: 2000,
  227. })
  228. }
  229. }
  230. if (currentTime > this.playedTime) {
  231. that.playedTime = currentTime //实时播放进度
  232. }
  233. that.video_real_time = currentTime //实时播放进度
  234. },
  235. /**
  236. * 提交课程时长
  237. */
  238. submitTimeLong({
  239. tabId,
  240. playDuration
  241. }, index, flag) {
  242. this.$u.api.training.videoTimeLongApi({
  243. tabId,
  244. playDuration
  245. }).then(res => {
  246. if (res.code === 200) {
  247. if (!flag) {
  248. this.$refs.uToast.show({
  249. title: '已记录章节时长!',
  250. type: 'success'
  251. })
  252. this.videoInfo = this.info.chapterList[index]
  253. this.form.tabId = this.videoInfo.id
  254. this.query.tabId = this.videoInfo.id
  255. this.videoIndex = index
  256. this.getClassesDetails(this.classesId);
  257. }
  258. } else {
  259. this.$refs.uToast.show({
  260. title: res.msg,
  261. type: 'error'
  262. })
  263. }
  264. })
  265. },
  266. /**
  267. * 获取评论列表
  268. */
  269. getCommentList() {
  270. this.$u.api.training.getClassesCommentApi(this.query).then(res => {
  271. if (res.code === 200) {
  272. this.total = Number(res.data.total);
  273. this.commentList = res.data.rows
  274. }
  275. })
  276. },
  277. /**
  278. * @param {Object} e 分页触发
  279. */
  280. pageChange(e) {
  281. this.query.pageNum = e.current
  282. this.getCommentList()
  283. },
  284. /**
  285. * 提交评论
  286. */
  287. submitCommet() {
  288. if (this.form.starLevel && this.form.content) {
  289. this.$u.api.training.addClassesCommentApi(this.form).then(res => {
  290. if (res.code === 200) {
  291. this.$refs.uToast.show({
  292. title: '评论成功!',
  293. type: 'success'
  294. })
  295. this.form.content = ''
  296. this.form.starLevel = 0
  297. this.getCommentList();
  298. } else {
  299. this.$refs.uToast.show({
  300. title: res.msg,
  301. type: 'error'
  302. })
  303. }
  304. })
  305. }
  306. if (!this.form.starLevel) {
  307. this.$refs.uToast.show({
  308. title: '请选择星级',
  309. type: 'warning'
  310. })
  311. }
  312. if (!this.form.content) {
  313. this.$refs.uToast.show({
  314. title: '请输入评论内容',
  315. type: 'warning'
  316. })
  317. }
  318. }
  319. }
  320. }
  321. </script>
  322. <style lang="scss" scoped>
  323. @import './onlineTrainingDetails.scss';
  324. </style>