detail.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. <template>
  2. <view>
  3. <view style="position: fixed;width: 100%;z-index: 999;background: #FFFFFF;top: 0;" id="top">
  4. <view class="video_box" v-if="!startStatus">
  5. <image :src="$method.splitImgHost(detail.coverUrl)" style="width: 100%;height: 460rpx;"></image>
  6. <image v-if="false" class="video_play" src="/static/play.png" @click="startVideo"></image>
  7. </view>
  8. <view v-else class="video_box" style="width: 100%;height: 460rpx;">
  9. <polyv-player
  10. id="playerVideo"
  11. playerId="playerVideo"
  12. height="460rpx"
  13. :vid="vid"
  14. :showSettingBtn="true"
  15. :enablePlayGesture="true"
  16. @statechange="onStateChange"
  17. :autoplay="autoplay"
  18. :isAllowSeek="isAllowSeek"
  19. :playbackRate="playbackRate"
  20. ></polyv-player>
  21. </view>
  22. <view>
  23. <u-row>
  24. <u-col span="10">
  25. <view class="video_t1">{{ detail.courseName }}</view>
  26. </u-col>
  27. <u-col span="2">
  28. <view class="video_t1_t" @click="openPhoto">
  29. <image src="/static/icon/jy_icon.png" style="width: 40rpx;height: 40rpx;"></image>
  30. 讲义
  31. </view>
  32. </u-col>
  33. </u-row>
  34. </view>
  35. <u-line color="#D6D6DB" />
  36. <view style="display: flex;justify-content: center;">
  37. <view style="width: 280px;">
  38. <u-tabs :list="list" font-size="24" bar-width="80" :current="current" @change="change" active-color="#007AFF"></u-tabs>
  39. </view>
  40. </view>
  41. <u-line color="#D6D6DB" />
  42. </view>
  43. <view class="box">
  44. <!--目录 -->
  45. <view v-show="current == 0">
  46. <view class="menuBox" v-for="(item, index) in reMenuList">
  47. <!--模块 -->
  48. <view v-if="item.type == 1"><courseModule :gradeId="gradeId" :isRebuild="true" :isBuy="true" :menuItem="item" :levelId="item.menuId"></courseModule></view>
  49. <!--章 -->
  50. <view v-if="item.type == 2"><courseChapter :gradeId="gradeId" :isRebuild="true" :isBuy="true" :menuItem="item" :levelId="'0-'+item.menuId"></courseChapter></view>
  51. <!--节 -->
  52. <view v-if="item.type == 3"><courseSection :gradeId="gradeId" :isRebuild="true" :isBuy="true" :menuItem="item" :levelId="'0-0-'+item.menuId"></courseSection></view>
  53. </view>
  54. </view>
  55. <!--目录 -->
  56. <view v-show="current == 1">
  57. <view class="menuBox" v-for="(item, index) in menuList">
  58. <!--模块 -->
  59. <view v-if="item.type == 1"><courseModule :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="item.menuId"></courseModule></view>
  60. <!--章 -->
  61. <view v-if="item.type == 2"><courseChapter :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="'0-'+item.menuId"></courseChapter></view>
  62. <!--节 -->
  63. <view v-if="item.type == 3"><courseSection :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="'0-0-'+item.menuId"></courseSection></view>
  64. </view>
  65. </view>
  66. <!--笔记 -->
  67. <view v-show="current == 2">
  68. <view v-if="noteList.length==0" style="text-align: center;">暂无笔记</view>
  69. <view class="inputBottom">
  70. <view style="width: 10%;"><image src="/static/icon/note3.png" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image></view>
  71. <view style="width: 73%;height: 88rpx;margin-bottom: 15rpx;">
  72. <u-input height="78" fixed="true" :placeholder="placeholder" type="textarea" :custom-style="inputStyle" v-model="noteValue" />
  73. </view>
  74. <view style="color: #007AFF;font-size: 30rpx;font-weight: bold;width: 15%;text-align: center;" @click="postNote">提交</view>
  75. </view>
  76. <view v-for="(item, index) in noteList" >
  77. <view class="dateBox">{{$method.timestampToTime(item.dateNote)}}</view>
  78. <view class="noteBox">
  79. <view v-for="(item1, index1) in item.userNotes" style="margin-top: 30rpx;" @click="jumpNote(item1)">
  80. <view style="display: flex;">
  81. <view>
  82. <view >
  83. <image src="/static/icon/note2.png" v-if="noteId!=item1.noteId" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image>
  84. <image src="/static/icon/note1.png" v-if="noteId==item1.noteId" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image>
  85. </view>
  86. <view class="title" style="width: 39rpx;height: 39rpx;margin:0 29rpx;">{{$method.secondToDate(item1.noteSecond)}}</view>
  87. </view>
  88. <view style="margin-left: 10rpx;">
  89. <view class="t2Content leftPadding">{{item1.sectionName}}</view>
  90. <view class="tBox2">
  91. {{item1.noteText}}
  92. </view>
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. </view>
  98. </view>
  99. <!--答疑 -->
  100. <view v-show="current == 3">
  101. <view class="inputBottom">
  102. <view style="width: 73%;height: 88rpx;margin-bottom: 15rpx;margin-left: 10% ;">
  103. <u-input height="78" fixed="true" :placeholder="placeholder" type="textarea" :custom-style="inputStyle" v-model="ctxValue" />
  104. </view>
  105. <view style="color: #007AFF;font-size: 30rpx;font-weight: bold;width: 15%;text-align: center;" @click="postContent">提交</view>
  106. </view>
  107. <view v-for="(item, index) in answerList" style="background-color: #FFFFFF;margin-bottom: 20rpx;">
  108. <view class="chat_box" @click.stop="clearCtx">
  109. <view style="display: flex;" >
  110. <view><image :src="$method.splitImgHost(item.avatar)" style="width: 64rpx;height: 64rpx;"></image></view>
  111. <view style="margin-left: 15rpx;">
  112. <view class="chat1">{{item.realname}}</view>
  113. <view class="chat2">{{$method.timestampToTime(item.createTime)}}</view>
  114. <view class="chat3">
  115. <text v-if="item.assignUserId>0">回复</text>
  116. <text v-if="item.assignUserId>0" style="color: #007AFF;">@{{item.assignRealname}}</text>
  117. {{item.answerText}}</view>
  118. </view>
  119. </view>
  120. <view class="btnReply" @click.stop="replyContent(item)" v-if="item.userId!=userInfo.userId">回复</view>
  121. <view v-else class="btnDel" @click.stop="delContent(item)">删除</view>
  122. </view>
  123. <u-line color="#D6D6DB" />
  124. </view>
  125. <view v-if="answerList.length==0" style="text-align: center;">
  126. 暂无记录
  127. </view>
  128. </view>
  129. </view>
  130. <!-- 播放前拍照start -->
  131. <u-popup v-model="photoPopup" mode="bottom" border-radius="32" :mask-close-able="false">
  132. <view class="photoBox">
  133. <view class="photoTop">
  134. <view class="sqzz" v-if="true">
  135. <u-icon name="close" color="#333333" size="30" @click="closePhoto"></u-icon>
  136. </view>
  137. <view class="centersq">
  138. 请正视手机屏幕
  139. </view>
  140. <view class="sqzz">
  141. </view>
  142. </view>
  143. <view class="photoCenter">
  144. <camera device-position="front" flash="off" @error="error" style="width: 100%; height: 100%" v-if="photoPopup"></camera>
  145. <view class="custom">
  146. <image src="@/pages2/static/zhezhao.png" mode=""></image>
  147. </view>
  148. </view>
  149. <view class="btnResult" @click="takePhoto">
  150. 拍照
  151. </view>
  152. </view>
  153. </u-popup>
  154. <!-- 播放前拍照end -->
  155. </view>
  156. </template>
  157. <script>
  158. import eventHub from '@/common/eventHub.js';
  159. import courseModule from '@/components/course/courseModule.vue';
  160. import courseChapter from '@/components/course/courseChapter.vue';
  161. import courseSection from '@/components/course/courseSection.vue';
  162. import { mapGetters } from 'vuex';
  163. export default {
  164. components: {
  165. courseModule,
  166. courseChapter,
  167. courseSection
  168. },
  169. data() {
  170. return {
  171. startStatus: false,
  172. detail: {},
  173. courseId: 0,
  174. placeholder: '您可以在这里输入笔记内容\n还可以点击左侧图标为笔记加上时间标记',
  175. inputStyle: {
  176. background: 'rgba(244, 244, 244, 0.98)',
  177. borderRadius: '24rpx',
  178. padding: '8rpx',
  179. marginBottom: '10rpx'
  180. },
  181. playbackRate: [0.5, 0.8, 1.0],
  182. list: [
  183. {
  184. name: '重修目录'
  185. },
  186. {
  187. name: '目录'
  188. },
  189. {
  190. name: '笔记'
  191. },
  192. {
  193. name: '答疑'
  194. }
  195. ],
  196. menuList: [
  197. ],
  198. current: 1,
  199. vid:'',
  200. goodsId:0,
  201. goodsData:{},
  202. photoPopup:false,
  203. goodsPlayConfig:null,
  204. autoplay:false,
  205. isAllowSeek:'no',
  206. playbackRate: [1.0],
  207. timer:null,
  208. goodsPhotographConfig:null,
  209. intervalTimeList:[],// 间隔拍照时长
  210. intervalTimeIndex:0 ,//当前处于哪个时间段拍照
  211. playTime:0 ,//页面播放时长,不含暂停
  212. currentTime:0,
  213. avatarUrl:'',
  214. ossAvatarUrl:'',
  215. studyDuration:0, // 当前视频时长
  216. gradeId:0,
  217. chapterId:0,
  218. moduleId:0,
  219. reMenuList: [],
  220. answerList: [],
  221. assignUserId:0,
  222. placeholder:'您可以在这里输入答疑内容',
  223. ctxValue:'',
  224. noteList:[],
  225. noteValue:'',
  226. noteId:0
  227. };
  228. },
  229. onUnload() {},
  230. computed: { ...mapGetters(['userInfo','playSectionId']) },
  231. onLoad(option) {
  232. this.courseId = option.id;
  233. this.goodsId = uni.getStorageSync('courseGoodsId');
  234. this.courseDetail();
  235. this.getGoodsDetail()
  236. this.getAnswerList()
  237. },
  238. onShow() {},
  239. onUnload() {
  240. if(this.playSectionId>0){
  241. //退出提交记录
  242. this.ossAvatarUrl = ""
  243. this.postStudyRecord()
  244. //清除正在播放的节ID
  245. this.$store.commit('setPlaySectionId', {playSectionId :0});
  246. }
  247. },
  248. mounted() {
  249. eventHub.$on('getSection', item => {
  250. if(this.timer){
  251. clearInterval(this.timer);
  252. }
  253. if(this.vid){
  254. //切换视频
  255. var polyvPlayerContext = this.selectComponent('#playerVideo');
  256. polyvPlayerContext.changeVid(item.recordingUrl)
  257. }else{
  258. this.vid = item.recordingUrl
  259. }
  260. this.startStatus = true
  261. this.startTime = 0
  262. //获取节笔记
  263. this.getNoteList()
  264. });
  265. eventHub.$on('levelId', item => {
  266. let arr = item.split('-')
  267. //点击节获取的各层级ID
  268. this.moduleId = arr[0]
  269. this.chapterId = arr[1]
  270. console.log(item,99)
  271. });
  272. },
  273. methods: {
  274. jumpNote(item){
  275. this.noteId = item.noteId
  276. this.$u.toast('即将跳到笔记位置');
  277. //跳到笔记时刻
  278. var polyvPlayerContext = this.selectComponent('#playerVideo');
  279. polyvPlayerContext.seek(item.noteSecond)
  280. polyvPlayerContext.play()
  281. },
  282. postNote() {
  283. let self = this;
  284. if(!(this.playSectionId>0)){
  285. this.$u.toast('目前无播放视频');
  286. retun
  287. }
  288. if(!this.noteValue){
  289. this.$u.toast('请输入内容');
  290. retun
  291. }
  292. var polyvPlayerContext = this.selectComponent('#playerVideo');
  293. let noteDate = this.$method.getZeroTime()
  294. let noteSecond= polyvPlayerContext.getCurrentTime()
  295. if(!noteSecond){
  296. this.$u.toast('视频暂未开始');
  297. retun
  298. }
  299. let data = {
  300. gradeId:this.gradeId,
  301. goodsId:this.goodsId,
  302. sectionId:this.playSectionId,
  303. courseId: this.courseId,
  304. noteText:this.noteValue,
  305. noteDate:noteDate,
  306. noteSecond:noteSecond}
  307. console.log(data,66)
  308. this.$api.postNote(data).then(res => {
  309. if (res.data.code == 200) {
  310. this.$u.toast('发布成功');
  311. self.getNoteList()
  312. this.noteValue = ''
  313. }
  314. });
  315. },
  316. getNoteList() {
  317. let self = this;
  318. this.$api.noteList({ sectionId:this.playSectionId,courseId: this.courseId,gradeId:this.gradeId,goodsId:this.goodsId }).then(res => {
  319. if (res.data.code == 200) {
  320. self.noteList = res.data.rows;
  321. }
  322. });
  323. },
  324. delAnswer(answerId) {
  325. let self = this;
  326. let data = { answerId: answerId,status:-1 }
  327. this.$api.delAnswer(data).then(res => {
  328. if (res.data.code == 200) {
  329. self.getAnswerList()
  330. }
  331. });
  332. },
  333. clearCtx(){
  334. console.log(4234)
  335. this.placeholder ='您可以在这里输入答疑内容'
  336. this.ctxValue = ''
  337. this.assignUserId=0
  338. },
  339. replyContent(item){
  340. this.assignUserId = item.userId
  341. this.placeholder = '@'+item.realname
  342. },
  343. delContent(item){
  344. this.delAnswer(item.answerId)
  345. },
  346. postAnswer() {
  347. let self = this;
  348. let data = { courseId: this.courseId,answerText:this.ctxValue }
  349. if(this.assignUserId>0){
  350. data.assignUserId = this.assignUserId
  351. }
  352. this.$api.postAnswer(data).then(res => {
  353. if (res.data.code == 200) {
  354. this.$u.toast('发布成功');
  355. self.getAnswerList()
  356. this.placeholder ='您可以在这里输入答疑内容'
  357. this.ctxValue = ''
  358. this.assignUserId=0
  359. }
  360. });
  361. },
  362. postContent(){
  363. if(!this.ctxValue){
  364. this.$u.toast('请输入内容');
  365. }
  366. this.postAnswer()
  367. },
  368. postStudyRecord(status=0) {
  369. let self = this;
  370. let data = {
  371. photo:self.ossAvatarUrl,
  372. sectionId:parseInt(self.playSectionId),
  373. goodsId:parseInt(self.goodsId),
  374. courseId:parseInt(self.courseId),
  375. studyDuration:parseInt(self.studyDuration),
  376. gradeId:parseInt(self.gradeId),
  377. chapterId:parseInt(self.chapterId),
  378. moduleId:parseInt(self.moduleId)
  379. }
  380. if(status>0){
  381. data.status = status
  382. }
  383. console.log("提交接口",data)
  384. this.$api.studyRecord(data).then(res => {
  385. console.log(res)
  386. });
  387. },
  388. uploadFile(options, int) {
  389. var self = this;
  390. return new Promise((resolve, reject) => {
  391. var data = {
  392. imageStatus: int
  393. };
  394. self.$api.aliyunpolicy(data).then(res => {
  395. if(res.data.code!=200){
  396. self.$method.showToast('签名错误'+JSON.stringify(res.data))
  397. return
  398. }
  399. var ossToken = res.data.data.resultContent;
  400. if(ossToken.host==null||ossToken.host==undefined){
  401. self.$method.showToast('上传路径报错'+JSON.stringify(res.data))
  402. return
  403. }
  404. uni.uploadFile({
  405. url: ossToken.host,
  406. name: 'file',
  407. filePath: options,
  408. fileType: 'image',
  409. header: {
  410. AuthorizationToken: 'WX ' + uni.getStorageSync('token')
  411. },
  412. formData: {
  413. key: ossToken.dir,
  414. OSSAccessKeyId: ossToken.accessid,
  415. policy: ossToken.policy,
  416. Signature: ossToken.signature,
  417. callback: ossToken.callback,
  418. success_action_status: 200
  419. },
  420. success: result => {
  421. if (result.statusCode === 200) {
  422. self.ossAvatarUrl = ossToken.dir;
  423. resolve();
  424. } else {
  425. uni.showToast({
  426. title: '上传失败',
  427. icon: 'none'
  428. });
  429. return;
  430. }
  431. },
  432. fail: error => {
  433. uni.showToast({
  434. title: '上传接口报错'+error,
  435. icon: 'none'
  436. });
  437. return;
  438. }
  439. });
  440. });
  441. });
  442. },
  443. imageInfos(){
  444. var self = this
  445. return new Promise((resolve, reject) => {
  446. uni.getImageInfo({
  447. src: self.avatarUrl,
  448. success: async res => {
  449. let canvasWidth = res.width; //图片原始长宽
  450. let canvasHeight = res.height;
  451. if (canvasWidth > 1000 || canvasHeight > 1000) {
  452. uni.compressImage({
  453. src: self.avatarUrl,
  454. quality: 75,
  455. width: '50%',
  456. height: '50%',
  457. success: async rest => {
  458. const waitUpload = await self.uploadFile(rest.tempFilePath, 0);
  459. resolve()
  460. }
  461. });
  462. } else {
  463. console.log('无需压缩');
  464. const waitUpload = await self.uploadFile(self.avatarUrl, 0);
  465. resolve()
  466. }
  467. }
  468. });
  469. });
  470. },
  471. timeEvent() {
  472. let self = this
  473. var polyvPlayerContext = this.selectComponent('#playerVideo');
  474. if (polyvPlayerContext != null) {
  475. let PlayCurrentTime = polyvPlayerContext.getCurrentTime();
  476. this.studyDuration = PlayCurrentTime
  477. if(this.currentTime<PlayCurrentTime){
  478. this.playTime+=(PlayCurrentTime-this.currentTime)
  479. this.currentTime = PlayCurrentTime
  480. }else{
  481. this.currentTime = PlayCurrentTime
  482. }
  483. //判断是否需要拍照
  484. if(this.intervalTimeList.length>this.intervalTimeIndex){
  485. let photoTime = Number(this.intervalTimeList[this.intervalTimeIndex]) * 60 //获取拍照秒数
  486. if(photoTime<this.playTime){
  487. //启动拍照
  488. //暂停
  489. polyvPlayerContext.exitFullScreen()
  490. polyvPlayerContext.pause()
  491. this.openPhoto();
  492. this.intervalTimeIndex++
  493. }
  494. }
  495. }
  496. },
  497. onStateChange(newstate, oldstate) {
  498. if (newstate.detail.newstate == 'playing') {
  499. //开始播放
  500. if(this.timer){
  501. clearInterval(this.timer);
  502. }
  503. this.timer = setInterval(this.timeEvent, 1500);//定时器
  504. }
  505. if (newstate.detail.newstate == 'pause') {
  506. //暂停提交记录
  507. /* this.ossAvatarUrl = ""
  508. this.postStudyRecord() */
  509. }
  510. if (newstate.detail.newstate == 'ended') {
  511. this.ossAvatarUrl = ""
  512. this.postStudyRecord(1)
  513. }
  514. },
  515. //拍照
  516. openPhoto(){
  517. this.photoPopup = true
  518. },
  519. async submit(){
  520. const waitYS = await this.imageInfos();
  521. this.postStudyRecord()//提交记录
  522. //恢复播放
  523. var polyvPlayerContext = this.selectComponent('#playerVideo');
  524. if (polyvPlayerContext != null) {
  525. polyvPlayerContext.play();
  526. }
  527. console.log(this.ossAvatarUrl,"拍照完成456")
  528. },
  529. //确认拍照
  530. takePhoto() {
  531. var self = this
  532. const ctx = uni.createCameraContext();
  533. ctx.takePhoto({
  534. quality: 'high',
  535. success: res => {
  536. console.log(res.tempImagePath)
  537. self.avatarUrl = res.tempImagePath
  538. self.submit()
  539. self.photoPopup = false
  540. },
  541. fail: err => {
  542. console.log(err)
  543. }
  544. });
  545. },
  546. //拍照报错
  547. error(e) {
  548. console.log(e.detail);
  549. },
  550. //关闭相机
  551. closePhoto(){
  552. this.photoPopup = false
  553. },
  554. getGoodsDetail(){
  555. let self = this
  556. this.$api.goodsDetail(this.goodsId).then(res => {
  557. self.goodsData = res.data.data;
  558. self.gradeId = self.goodsData.gradeId
  559. self.getMenuList();
  560. self.getReMenuList() //获取重修目录
  561. if(self.goodsData.goodsPlayConfig){
  562. self.goodsPlayConfig = JSON.parse(self.goodsData.goodsPlayConfig);
  563. if(self.goodsPlayConfig.autoPlay>0){
  564. self.autoplay = true
  565. }
  566. if(self.goodsPlayConfig.drag>0){
  567. self.isAllowSeek = "yes"
  568. }
  569. if(self.goodsPlayConfig.speed>0){
  570. self.playbackRate = [0.5,0.8,1.0,1.25,1.5,2.0]
  571. }
  572. }
  573. if(self.goodsData.goodsPhotographConfig){
  574. self.goodsPhotographConfig = JSON.parse(self.goodsData.goodsPhotographConfig);
  575. if(self.goodsPhotographConfig.intervalTime){
  576. self.intervalTimeList = self.goodsPhotographConfig.intervalTime.split(',')
  577. }
  578. }
  579. })
  580. },
  581. startVideo() {
  582. this.startStatus = true;
  583. },
  584. getAnswerList() {
  585. let self = this;
  586. this.$api.answerList({ courseId: this.courseId }).then(res => {
  587. if (res.data.code == 200) {
  588. self.answerList = res.data.rows;
  589. }
  590. });
  591. },
  592. getReMenuList() {
  593. let self = this;
  594. this.$api.reMenuList({ courseId: this.courseId,rebuild:1,gradeId:this.gradeId }).then(res => {
  595. if (res.data.code == 200) {
  596. for (let i = 0; i < res.data.rows.length; i++) {
  597. let item = res.data.rows[i];
  598. item.down = true;
  599. item.id = item.menuId;
  600. item.name = item.menuName;
  601. }
  602. self.reMenuList = res.data.rows;
  603. }
  604. });
  605. },
  606. getMenuList() {
  607. let self = this;
  608. this.$api.reMenuList({ courseId: this.courseId,gradeId:this.gradeId }).then(res => {
  609. if (res.data.code == 200) {
  610. for (let i = 0; i < res.data.rows.length; i++) {
  611. let item = res.data.rows[i];
  612. item.down = true;
  613. item.id = item.menuId;
  614. item.name = item.menuName;
  615. }
  616. self.menuList = res.data.rows;
  617. }
  618. });
  619. },
  620. courseDetail() {
  621. let self = this;
  622. this.$api.courseDetail(this.courseId).then(res => {
  623. if (res.data.code == 200) {
  624. self.detail = res.data.data;
  625. self.gradeId = self.detail.gradeId
  626. }
  627. });
  628. },
  629. open(item) {
  630. item.showChildren = !item.showChildren;
  631. },
  632. change(index) {
  633. this.current = index;
  634. }
  635. }
  636. };
  637. </script>
  638. <style lang="scss" scope>
  639. .btnReply{
  640. width: 80rpx;
  641. height: 40rpx;
  642. background: #E3F0FF;
  643. border-radius: 16rpx;
  644. text-align: center;
  645. color: #007AFF;
  646. }
  647. .btnDel{
  648. width: 80rpx;
  649. height: 40rpx;
  650. background: #FFEDF0;
  651. border-radius: 16rpx;
  652. text-align: center;
  653. color: #FF2D55;
  654. }
  655. .btnReply{
  656. width: 80rpx;
  657. height: 40rpx;
  658. background: #E3F0FF;
  659. border-radius: 16rpx;
  660. font-size: 24rpx;
  661. }
  662. .photoBox{
  663. .photoTop{
  664. height: 74upx;
  665. display: flex;
  666. align-items: center;
  667. justify-content: space-between;
  668. padding: 0upx 38upx;
  669. .sqzz{
  670. width: 28upx;
  671. height: 28upx;
  672. display: flex;
  673. align-items: center;
  674. justify-content: center;
  675. }
  676. .centersq{
  677. color: #333;
  678. font-size: 30upx;
  679. font-weight: 500;
  680. }
  681. }
  682. .photoCenter{
  683. width: 750upx;
  684. height: 979upx;
  685. position: relative;
  686. .custom{
  687. width: 750upx;
  688. height: 979upx;
  689. position: absolute;
  690. top: 0;
  691. left: 0;
  692. image{
  693. width: 100%;
  694. height: 100%;
  695. }
  696. }
  697. }
  698. .btnResult{
  699. height: 100upx;
  700. width: 100%;
  701. background-color: #07c160;
  702. text-align: center;
  703. line-height: 100upx;
  704. color: #fff;
  705. font-size: 32upx;
  706. font-weight: bold;
  707. }
  708. }
  709. .chat_box {
  710. display: flex;
  711. padding: 20rpx;
  712. justify-content: space-between;
  713. }
  714. .chat3 {
  715. font-size: 30rpx;
  716. font-family: PingFang SC;
  717. font-weight: 500;
  718. color: #666666;
  719. margin-top: 10rpx;
  720. }
  721. .chat2 {
  722. font-size: 20rpx;
  723. font-family: PingFang SC;
  724. font-weight: 500;
  725. color: #999999;
  726. margin-top: 10rpx;
  727. }
  728. .chat1 {
  729. font-size: 24rpx;
  730. font-family: PingFang SC;
  731. font-weight: 500;
  732. color: #333333;
  733. }
  734. .leftPadding {
  735. margin-left: 8rpx;
  736. }
  737. .t2Content {
  738. font-size: 28rpx;
  739. font-family: PingFang SC;
  740. font-weight: bold;
  741. color: #999999;
  742. line-height: 48rpx;
  743. }
  744. .tBox2 {
  745. display: flex;
  746. padding-top: 10rpx;
  747. color: #333333;
  748. font-size: 30rpx;
  749. }
  750. .tBox {
  751. display: flex;
  752. align-items: center;
  753. padding-top: 10rpx;
  754. }
  755. .title {
  756. font-size: 24rpx;
  757. color: #999999;
  758. }
  759. page {
  760. padding-top: 10px;
  761. padding-top: constant(safe-area-inset-top);
  762. padding-top: env(safe-area-inset-top);
  763. }
  764. .inputBottom {
  765. position: fixed;
  766. left: 0;
  767. bottom: 0;
  768. background: #ffffff;
  769. height: 98rpx;
  770. display: flex;
  771. align-items: center;
  772. width: 100%;
  773. }
  774. .noteBox {
  775. width: 100%;
  776. background: #ffffff;
  777. padding: 10rpx;
  778. border-radius: 16rpx;
  779. }
  780. .dateBox {
  781. width: 216rpx;
  782. height: 48rpx;
  783. background: #ffffff;
  784. border-radius: 24rpx;
  785. font-size: 24rpx;
  786. color: #666666;
  787. text-align: center;
  788. line-height: 48rpx;
  789. margin: 20rpx 0;
  790. }
  791. .t_content1 {
  792. color: #007aff;
  793. margin-left: 10rpx;
  794. }
  795. .tag1 {
  796. border: 2rpx solid #007aff;
  797. border-radius: 8rpx;
  798. font-size: 20rpx;
  799. color: #007aff;
  800. padding: 5rpx;
  801. }
  802. .b_title {
  803. color: #333333;
  804. font-size: 30rpx;
  805. font-weight: bold;
  806. }
  807. page {
  808. background: #eaeef1;
  809. }
  810. .menuBox {
  811. width: 100%;
  812. background: #ffffff;
  813. border-radius: 16rpx;
  814. padding: 20rpx;
  815. margin-bottom: 20rpx;
  816. }
  817. .btnspric {
  818. border-top: 1rpx solid #eee;
  819. display: flex;
  820. align-items: center;
  821. justify-content: space-between;
  822. height: 108rpx;
  823. padding-left: 43rpx;
  824. padding-right: 32rpx;
  825. }
  826. .btnspric > .lefprL {
  827. font-size: 36rpx;
  828. color: #0c141f;
  829. font-weight: bold;
  830. }
  831. .btnspric > .lefprR {
  832. padding: 0rpx 24rpx;
  833. height: 60rpx;
  834. line-height: 60rpx;
  835. text-align: center;
  836. color: #fff;
  837. background: #32467b;
  838. border-radius: 24rpx;
  839. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  840. }
  841. .yhj,
  842. .hdyhj {
  843. padding: 24rpx 29rpx 24rpx 34rpx;
  844. }
  845. .yhj {
  846. border-bottom: 16rpx solid #f9f9f9;
  847. }
  848. .yhjtit {
  849. font-size: 30rpx;
  850. color: #0c141f;
  851. font-weight: 500;
  852. margin-bottom: 14rpx;
  853. }
  854. .yhjList {
  855. display: flex;
  856. align-items: center;
  857. justify-content: space-between;
  858. margin-bottom: 14rpx;
  859. }
  860. .yhjList > .yhjLefts {
  861. display: flex;
  862. align-items: center;
  863. }
  864. .yhjLefts > .yhl {
  865. color: #32467b;
  866. font-size: 30rpx;
  867. margin-right: 31rpx;
  868. }
  869. .yhjLefts > .yhbq {
  870. font-size: 24rpx;
  871. color: #ff9500;
  872. border-radius: 18rpx;
  873. background-color: rgba(255, 149, 0, 0.2);
  874. border: 2rpx solid #ff9500;
  875. height: 38rpx;
  876. line-height: 38rpx;
  877. padding: 0rpx 16rpx;
  878. }
  879. .ts {
  880. font-size: 24rpx;
  881. color: #999;
  882. margin: 14rpx 0rpx;
  883. padding-right: 29rpx;
  884. padding-left: 34rpx;
  885. }
  886. .yh {
  887. padding-top: 20rpx;
  888. }
  889. .yh > .yhtitle {
  890. display: flex;
  891. align-items: center;
  892. justify-content: space-between;
  893. padding-right: 29rpx;
  894. padding-left: 34rpx;
  895. }
  896. .priceBxs {
  897. display: flex;
  898. align-items: center;
  899. }
  900. .priceBxs > .pricleft {
  901. border-radius: 24rpx;
  902. border: 1rpx solid #e91313;
  903. background-color: rgba(233, 19, 19, 0.1);
  904. padding: 0rpx 18rpx;
  905. height: 49rpx;
  906. line-height: 49rpx;
  907. text-align: center;
  908. font-size: 30rpx;
  909. font-weight: 500;
  910. color: #e91313;
  911. margin-right: 13rpx;
  912. }
  913. .topBox {
  914. padding: 32rpx 32rpx 24rpx;
  915. border-bottom: 1rpx solid #eeeeee;
  916. }
  917. .topBox > .boldFonstType {
  918. font-weight: 500;
  919. font-size: 30rpx;
  920. margin: 16rpx 0rpx 23rpx;
  921. }
  922. .topBox > .firstTopL {
  923. display: flex;
  924. align-items: center;
  925. }
  926. .topBox > .firstTopL > .imageBs {
  927. width: 331rpx;
  928. height: 160rpx;
  929. border-radius: 6rpx;
  930. overflow: hidden;
  931. margin-right: 8rpx;
  932. box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(47, 67, 121, 0.08);
  933. }
  934. .topBox > .firstTopL > .imageBs > image {
  935. width: 100%;
  936. height: 100%;
  937. }
  938. .topBox > .firstTopL > .textBs {
  939. font-size: 30rpx;
  940. font-weight: bold;
  941. color: #0c141f;
  942. }
  943. .content {
  944. padding: 24rpx;
  945. text-align: left;
  946. }
  947. .catalogBox {
  948. display: flex;
  949. align-items: center;
  950. flex-wrap: nowrap;
  951. overflow-x: auto;
  952. padding-left: 38rpx;
  953. max-height: 305rpx;
  954. overflow-y: auto;
  955. transition: all 0.4s;
  956. }
  957. .catalogBox > .catalogA {
  958. min-width: 200rpx;
  959. height: 48rpx;
  960. line-height: 48rpx;
  961. // text-align: center;
  962. border: 2rpx solid transparent;
  963. white-space: nowrap;
  964. text-overflow: ellipsis;
  965. overflow: hidden;
  966. word-break: break-all;
  967. border-radius: 10rpx;
  968. background: rgba(22, 119, 255, 0.05);
  969. padding-left: 19rpx;
  970. box-sizing: border-box;
  971. padding-right: 15rpx;
  972. margin-right: 16rpx;
  973. margin-bottom: 20rpx;
  974. margin-top: 15rpx;
  975. font-size: 24rpx;
  976. color: #666;
  977. }
  978. .catalogBox > .activesq {
  979. border-color: #1677ff;
  980. }
  981. .changeCatalogBox {
  982. display: block;
  983. }
  984. .catalogBox::-webkit-scrollbar {
  985. display: none; /* Chrome Safari */
  986. }
  987. .box {
  988. position: relative;
  989. top: 650rpx;
  990. padding-bottom: 88rpx;
  991. margin: 20rpx;
  992. }
  993. .price_t2 {
  994. font-size: 18rpx;
  995. font-family: PingFang SC;
  996. font-weight: 500;
  997. text-decoration: line-through;
  998. color: #999999;
  999. }
  1000. .price_t1 {
  1001. font-size: 33rpx;
  1002. font-family: PingFang SC;
  1003. font-weight: bold;
  1004. color: #e91313;
  1005. }
  1006. .sc_t {
  1007. font-size: 22rpx;
  1008. color: #000000;
  1009. }
  1010. .sc {
  1011. width: 29rpx;
  1012. height: 29rpx;
  1013. }
  1014. .buy {
  1015. width: 138rpx;
  1016. height: 48rpx;
  1017. line-height: 48rpx;
  1018. background: #32467b;
  1019. border-radius: 10rpx;
  1020. color: #ffffff;
  1021. font-size: 28rpx;
  1022. text-align: center;
  1023. vertical-align: middle;
  1024. position: absolute;
  1025. right: 30rpx;
  1026. }
  1027. .video_body {
  1028. padding-bottom: 96rpx;
  1029. }
  1030. .footer_tab {
  1031. position: fixed;
  1032. bottom: 0;
  1033. height: 96rpx;
  1034. width: 100%;
  1035. background-color: #ffffff;
  1036. }
  1037. .tj_box {
  1038. width: 50%;
  1039. display: inline-block;
  1040. text-align: center;
  1041. margin: 10rpx 0;
  1042. }
  1043. .teacher_t {
  1044. font-size: 24rpx;
  1045. font-family: PingFang SC;
  1046. font-weight: 400;
  1047. color: #666666;
  1048. line-height: 36rpx;
  1049. margin-left: 15rpx;
  1050. }
  1051. .teacher_img {
  1052. width: 87rpx;
  1053. height: 129rpx;
  1054. }
  1055. .t2 {
  1056. font-size: 24rpx;
  1057. font-family: PingFang SC;
  1058. color: #666666;
  1059. line-height: 36rpx;
  1060. margin: 15rpx;
  1061. }
  1062. .r_t2 {
  1063. width: 201rpx;
  1064. height: 49rpx;
  1065. background: rgba(22, 119, 255, 0.05);
  1066. border: 1rpx solid #32467b;
  1067. border-radius: 16rpx;
  1068. color: #666666;
  1069. font-size: 23rpx;
  1070. text-align: center;
  1071. display: flex;
  1072. align-items: center;
  1073. padding: 5rpx;
  1074. }
  1075. .scroll_box {
  1076. width: 100%;
  1077. height: 60rpx;
  1078. background: #ffffff;
  1079. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  1080. white-space: nowrap;
  1081. overflow: hidden;
  1082. margin: 15rpx 0;
  1083. }
  1084. .r_sliper {
  1085. padding: 0 20rpx;
  1086. }
  1087. .top_line {
  1088. width: 6rpx;
  1089. height: 22rpx;
  1090. background: #32467b;
  1091. margin-right: 10rpx;
  1092. }
  1093. .video_t2 {
  1094. font-size: 24rpx;
  1095. font-family: PingFang SC;
  1096. font-weight: 500;
  1097. color: #666666;
  1098. }
  1099. .video_t1 {
  1100. height: 80rpx;
  1101. color: #333333;
  1102. line-height: 80rpx;
  1103. font-size: 30rpx;
  1104. font-family: PingFang SC;
  1105. font-weight: bold;
  1106. color: #333333;
  1107. }
  1108. .video_t1_t {
  1109. display: flex;
  1110. flex-direction: column;
  1111. height: 80rpx;
  1112. color: #333333;
  1113. text-align: center;
  1114. align-items: center;
  1115. border-left: solid 1px #d6d6db;
  1116. }
  1117. .video_play {
  1118. position: absolute;
  1119. width: 95rpx;
  1120. height: 95rpx;
  1121. top: 0;
  1122. left: 0;
  1123. right: 0;
  1124. bottom: 0;
  1125. margin: auto;
  1126. }
  1127. .video_box {
  1128. position: relative;
  1129. }
  1130. .rotoct {
  1131. transform: rotate(90deg);
  1132. }
  1133. </style>