detail.vue 26 KB

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