detail.vue 28 KB

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