coursedetail.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <view class="column">
  3. <view class="video-box" >
  4. <video id="myVideo" :src='listdetail.videoUrl' show-mute-btn='false'
  5. vslide-gesture-in-fullscreen='true' loop='true' enable-progress-gesture='true'
  6. enable-danmu controls='true' autoplay="true" object-fit='contain' show-center-play-btn='true'
  7. class="videotop" :playback-rate="playbackRate"></video>
  8. </view>
  9. <view class="speed-controls">
  10. <view @click="changeSpeed(item.value,index)" v-for="(item,index) in speadvideo"
  11. :key="index" :class="actTime==index?'actstyle':''">{{item.name}}</view>
  12. </view>
  13. <view class="title-content" id="title-content">
  14. <!-- 课程标题 -->
  15. <view >
  16. {{listdetail.title}}
  17. </view>
  18. <view class="fs24" style="color: #666;font-weight: normal;">
  19. {{listdetail.description?listdetail.description:""}}
  20. </view>
  21. <view class="fs24" style="color: #999;font-weight: normal;">课程视频时长:{{formatSeconds(listdetail.duration)}}</view>
  22. </view>
  23. <!-- 问题 -->
  24. <view class="ques-content ">
  25. <view class="ques-content-tit">问答题</view>
  26. <view class="center fs32" v-if="listdetail.questionBankList.length<1" style="color: #666;">暂无问答题</view>
  27. <view v-for="(item,index) in listdetail.questionBankList" :key="index">
  28. <view class="ques-title">
  29. <text>{{index + 1}}.</text>
  30. <view class="ques-type" v-show="item.type == 1 || item.type == 2">
  31. {{item.type == 1 ? '单选' : item.type == 2 ? '多选' : ''}}
  32. </view>
  33. <text >{{item.title}}</text>
  34. </view>
  35. <view :class="option.isAnswer== 1 ?'ques-option ques-option-active':'ques-option'"
  36. v-for="(option,idx) in item.question" :key="idx">
  37. <view>
  38. {{numberToLetter(idx)}}.
  39. </view>
  40. <view>{{option.name}}</view>
  41. </view>
  42. </view>
  43. </view>
  44. <!-- <view class="footer" v-if="!viewload">
  45. <view class="justify-between" >
  46. <button open-type="share" class="copybtn flex-1">分享课程</button>
  47. <view class="copybtn flex-1" @click="copyshareLink()">复制分享链接</view>
  48. </view>
  49. </view> -->
  50. <u-loading-page :loading="viewload" iconSize="32" loadingColor="#3c9cff" fontSize="20"
  51. :loading-text="loadingtext" ></u-loading-page>
  52. </view>
  53. </template>
  54. <script>
  55. import {
  56. getcourseDetail,
  57. sharecourselink
  58. } from '@/api/manageCompany'
  59. import {
  60. numberToLetter
  61. } from "@/utils/tools.js"
  62. export default {
  63. data() {
  64. return {
  65. viewload:true,
  66. loadingtext:"数据加载中...",
  67. videoId:'',
  68. listdetail:[],
  69. user:{},
  70. copylink:'',
  71. id:'',
  72. periodId:'',
  73. imgs:this.$store.state.imgpath+'/app/image/logo.png',
  74. playbackRate: 1.0, // 默认1倍速
  75. videoContext: null,
  76. actTime:0,
  77. speadvideo:[
  78. {
  79. name:'1.0倍速',
  80. value:1
  81. },
  82. {
  83. name:'1.5倍速',
  84. value:1.5
  85. },
  86. {
  87. name:'2.0倍速',
  88. value:2
  89. }
  90. ]
  91. }
  92. },
  93. mounted() {
  94. // 创建视频上下文
  95. this.videoContext = uni.createVideoContext('myVideo', this);
  96. },
  97. onLoad(option) {
  98. this.videoId=option.videoId
  99. this.id=option.id
  100. this.periodId=option.periodId
  101. },
  102. onShow() {
  103. this.getdetail()
  104. this.user = uni.getStorageSync("companyUserInfo") ? JSON.parse(uni.getStorageSync("companyUserInfo")) : {}
  105. },
  106. computed: {
  107. imgPath() {
  108. // 处理空值,返回默认路径或空字符串
  109. // if (!this.$store.state.imgpath) {
  110. // return '' // 本地默认图
  111. // }
  112. return this.$store.state.imgpath
  113. }
  114. },
  115. // onShareAppMessage() {
  116. // const course={
  117. // companyId:this.user.companyId,
  118. // companyUserId:this.user.userId,
  119. // id:this.id,
  120. // courseId:this.listdetail.courseId,
  121. // videoId:this.videoId,
  122. // periodId:this.periodId
  123. // }
  124. // console.log(course)
  125. // return {
  126. // title: this.listdetail.title, // 分享卡片标题
  127. // path: 'pages_course/videovip' + "?course=" +JSON.stringify(course) , // 目标页面路径
  128. // // 携带参数:将当前页面的数据拼接到路径中
  129. // imageUrl: this.listdetail.thumbnail||this.imgs, // 分享卡片封面图(可选)
  130. // success: (res) => {
  131. // console.log("分享成功", res);
  132. // },
  133. // fail: (err) => {
  134. // console.log("分享失败", err);
  135. // },
  136. // }
  137. // },
  138. methods: {
  139. changeSpeed(rate,index) {
  140. console.log(rate,index)
  141. this.actTime=index
  142. this.playbackRate = rate;
  143. // 更新播放速率
  144. if (this.videoContext) {
  145. this.videoContext.playbackRate(rate);
  146. }
  147. },
  148. numberToLetter(num) {
  149. // 将数字转换为字母的 ASCII 码
  150. let letterCode = num + 65;
  151. // 将 ASCII 码转换为大写字母
  152. let letter = String.fromCharCode(letterCode);
  153. return letter;
  154. },
  155. //转化时间格式
  156. formatSeconds(seconds) {
  157. const hours = Math.floor(seconds / 3600);
  158. const minutes = Math.floor((seconds % 3600) / 60);
  159. const remainingSeconds = seconds % 60;
  160. // 补零函数:确保两位数显示
  161. const pad = (num) => num.toString().padStart(2, '0');
  162. return `${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`;
  163. },
  164. // 获取视频详情
  165. getdetail() {
  166. const param = {
  167. videoId:this.videoId
  168. }
  169. getcourseDetail(param).then(res => {
  170. if(res.code==200){
  171. this.viewload=false
  172. this.listdetail=res.data
  173. this.listdetail.questionBankList= this.listdetail.questionBankList.map(item => ({
  174. ...item,
  175. question: JSON.parse(item.question),
  176. answer: '',
  177. }))
  178. }else{
  179. uni.showToast({
  180. title: res.msg,
  181. icon: 'none',
  182. });
  183. }
  184. })
  185. },
  186. copyshareLink(){
  187. const params = {
  188. companyId: this.user.companyId,
  189. companyUserId: this.user.userId,
  190. courseId: this.listdetail.courseId,
  191. time: this.time,
  192. videoId: this.listdetail.videoId,
  193. id: Number(this.id),
  194. }
  195. sharecourselink(params).then(res => {
  196. if (res.code == 200) {
  197. this.copylink = res.url
  198. // if (this.copylink.startsWith('http://')) {
  199. // this.copylink = this.copylink.replace('http://', 'https://');
  200. // }
  201. // console.log(this.copylink)
  202. setTimeout(() => {
  203. uni.setClipboardData({
  204. data: this.copylink,
  205. success: () => {
  206. uni.showToast({
  207. title: '链接已复制',
  208. icon: 'none',
  209. duration: 2000
  210. });
  211. },
  212. fail: () => {
  213. uni.showToast({
  214. title: '复制失败',
  215. icon: 'none'
  216. });
  217. }
  218. });
  219. }, 100)
  220. console.log(this.copylink)
  221. } else {
  222. uni.showToast({
  223. icon: 'none',
  224. title: res.msg
  225. })
  226. }
  227. })
  228. console.log(123)
  229. }
  230. }
  231. }
  232. </script>
  233. <style scoped lang="scss">
  234. .actstyle{
  235. background-color: #FF5C03;
  236. color: #fff;
  237. border: 2rpx solid #FF5C03 !important;
  238. }
  239. .speed-controls {
  240. margin-top: 20rpx;
  241. display: flex;
  242. justify-content: space-around;
  243. margin-bottom: 16rpx;
  244. view{
  245. height: 50rpx;
  246. line-height: 46rpx;
  247. width: 120rpx;
  248. font-size: 24rpx;
  249. border-radius: 30rpx;
  250. text-align: center;
  251. border: 2rpx solid #a5a5a5;
  252. }
  253. }
  254. .video-box {
  255. width: 100%;
  256. height: 420rpx;
  257. overflow: hidden;
  258. position: relative;
  259. #myVideo {
  260. width: 100%;
  261. height: 100%;
  262. }
  263. }
  264. .title-content {
  265. padding: 20rpx 32rpx;
  266. background-color: #fff;
  267. font-size: 28rpx;
  268. font-weight: bold;
  269. line-height: 1.6;
  270. }
  271. .ques-content-tit {
  272. font-family: PingFang SC, PingFang SC;
  273. font-weight: 600;
  274. font-size: 36rpx;
  275. color: #222222;
  276. }
  277. .ques-content {
  278. background-color: #fff;
  279. margin-top: 20rpx;
  280. padding: 32rpx 32rpx;
  281. padding-bottom: 140rpx;
  282. box-sizing: border-box;
  283. ont-family: PingFang SC, PingFang SC;
  284. font-weight: 400;
  285. font-size: 28rpx;
  286. color: #222222;
  287. }
  288. .ques-title {
  289. margin: 32rpx 0 34rpx 0;
  290. font-weight: 500;
  291. font-size: 32rpx;
  292. white-space: normal;
  293. }
  294. .ques-type {
  295. flex-shrink: 0;
  296. min-width: 72rpx;
  297. height: 40rpx;
  298. padding: 0 12rpx;
  299. margin: 0 12rpx;
  300. box-sizing: border-box;
  301. background: #ff8901;
  302. border-radius: 8rpx 8rpx 8rpx 8rpx;
  303. line-height: 40rpx;
  304. text-align: center;
  305. font-family: PingFang SC, PingFang SC;
  306. font-weight: 400;
  307. font-size: 24rpx;
  308. color: #FFFFFF;
  309. display: inline-block;
  310. }
  311. .ques-option {
  312. min-height: 88rpx;
  313. padding: 24rpx 32rpx;
  314. box-sizing: border-box;
  315. margin-bottom: 24rpx;
  316. background: #F5F7FA;
  317. border-radius: 16rpx 16rpx 16rpx 16rpx;
  318. display: flex;
  319. align-items: center;
  320. &-active {
  321. color: #1db131 !important;
  322. background: #e8fcee !important;
  323. }
  324. }
  325. .footer {
  326. border-top: 1rpx solid #ededef;
  327. background: #fff;
  328. width: 100%;
  329. position: fixed;
  330. bottom: 0;
  331. padding: 24rpx 32rpx;
  332. box-sizing: border-box;
  333. z-index: 9;
  334. .copybtn {
  335. background: #FF5C03;
  336. color: #fff;
  337. text-align: center;
  338. font-size: 28rpx;
  339. border-radius: 80rpx;
  340. padding: 20rpx 0;
  341. }
  342. }
  343. </style>