detail.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  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="false">
  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:Number(self.gradeId),
  293. goodsId:Number(self.goodsId),
  294. sectionId:Number(self.playSectionId),
  295. courseId: Number(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=this.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(data.studyDuration<=5){ //5秒内不上传记录
  413. return
  414. }
  415. if(status>0){
  416. data.status = status
  417. }
  418. console.log("提交接口",data)
  419. this.$api.studyRecord(data).then(res => {
  420. console.log(res)
  421. });
  422. },
  423. uploadFile(options, int) {
  424. var self = this;
  425. return new Promise((resolve, reject) => {
  426. var data = {
  427. imageStatus: int
  428. };
  429. self.$api.aliyunpolicy(data).then(res => {
  430. if(res.data.code!=200){
  431. self.$method.showToast('签名错误'+JSON.stringify(res.data))
  432. return
  433. }
  434. var ossToken = res.data.data.resultContent;
  435. if(ossToken.host==null||ossToken.host==undefined){
  436. self.$method.showToast('上传路径报错'+JSON.stringify(res.data))
  437. return
  438. }
  439. uni.uploadFile({
  440. url: ossToken.host,
  441. name: 'file',
  442. filePath: options,
  443. fileType: 'image',
  444. header: {
  445. AuthorizationToken: 'WX ' + uni.getStorageSync('token')
  446. },
  447. formData: {
  448. key: ossToken.dir,
  449. OSSAccessKeyId: ossToken.accessid,
  450. policy: ossToken.policy,
  451. Signature: ossToken.signature,
  452. callback: ossToken.callback,
  453. success_action_status: 200
  454. },
  455. success: result => {
  456. if (result.statusCode === 200) {
  457. self.ossAvatarUrl = ossToken.dir;
  458. resolve();
  459. } else {
  460. uni.showToast({
  461. title: '上传失败',
  462. icon: 'none'
  463. });
  464. return;
  465. }
  466. },
  467. fail: error => {
  468. uni.showToast({
  469. title: '上传接口报错'+error,
  470. icon: 'none'
  471. });
  472. return;
  473. }
  474. });
  475. });
  476. });
  477. },
  478. imageInfos(){
  479. var self = this
  480. return new Promise((resolve, reject) => {
  481. uni.getImageInfo({
  482. src: self.avatarUrl,
  483. success: async res => {
  484. let canvasWidth = res.width; //图片原始长宽
  485. let canvasHeight = res.height;
  486. if (canvasWidth > 1000 || canvasHeight > 1000) {
  487. uni.compressImage({
  488. src: self.avatarUrl,
  489. quality: 75,
  490. width: '50%',
  491. height: '50%',
  492. success: async rest => {
  493. const waitUpload = await self.uploadFile(rest.tempFilePath, 0);
  494. resolve()
  495. }
  496. });
  497. } else {
  498. console.log('无需压缩');
  499. const waitUpload = await self.uploadFile(self.avatarUrl, 0);
  500. resolve()
  501. }
  502. }
  503. });
  504. });
  505. },
  506. timeEvent() {
  507. let self = this
  508. var polyvPlayerContext = this.selectComponent('#playerVideo');
  509. if (polyvPlayerContext != null) {
  510. let PlayCurrentTime = polyvPlayerContext.getVideoPlayDuration();
  511. this.studyDuration = PlayCurrentTime
  512. if(this.currentTime<PlayCurrentTime){
  513. this.playTime+=(PlayCurrentTime-this.currentTime)
  514. this.currentTime = PlayCurrentTime
  515. }else{
  516. this.currentTime = PlayCurrentTime
  517. }
  518. //判断是否需要拍照
  519. if(this.intervalTimeList.length>this.intervalTimeIndex){
  520. let photoTime = Number(this.intervalTimeList[this.intervalTimeIndex]) * 60 //获取拍照秒数
  521. if(photoTime<this.playTime){
  522. //启动拍照
  523. //暂停
  524. polyvPlayerContext.exitFullScreen()
  525. polyvPlayerContext.pause()
  526. this.openPhoto();
  527. this.intervalTimeIndex++
  528. }
  529. }
  530. }
  531. },
  532. onStateChange(newstate, oldstate) {
  533. console.log(newstate,6989)
  534. if (newstate.detail.newstate == 'playing') {
  535. if(this.needSeek){
  536. var polyvPlayerContext = this.selectComponent('#playerVideo');
  537. polyvPlayerContext.seek(this.recordObj.studyDuration)
  538. polyvPlayerContext.play()
  539. this.needSeek = false
  540. }
  541. //开始播放
  542. if(this.timer){
  543. clearInterval(this.timer);
  544. }
  545. this.timer = setInterval(this.timeEvent, 1500);//定时器
  546. }
  547. if (newstate.detail.newstate == 'pause') {
  548. //暂停提交记录
  549. /* this.ossAvatarUrl = ""
  550. this.postStudyRecord() */
  551. }
  552. if (newstate.detail.newstate == 'ended') {
  553. this.ossAvatarUrl = ""
  554. this.postStudyRecord(1)
  555. }
  556. },
  557. //拍照
  558. openPhoto(){
  559. this.photoPopup = true
  560. },
  561. async submit(){
  562. const waitYS = await this.imageInfos();
  563. this.postStudyRecord()//提交记录
  564. //恢复播放
  565. var polyvPlayerContext = this.selectComponent('#playerVideo');
  566. if (polyvPlayerContext != null) {
  567. polyvPlayerContext.play();
  568. }
  569. console.log(this.ossAvatarUrl,"拍照完成456")
  570. },
  571. //确认拍照
  572. takePhoto() {
  573. var self = this
  574. const ctx = uni.createCameraContext();
  575. ctx.takePhoto({
  576. quality: 'high',
  577. success: res => {
  578. console.log(res.tempImagePath)
  579. self.avatarUrl = res.tempImagePath
  580. self.submit()
  581. self.photoPopup = false
  582. },
  583. fail: err => {
  584. console.log(err)
  585. }
  586. });
  587. },
  588. //拍照报错
  589. error(e) {
  590. console.log(e.detail);
  591. },
  592. //关闭相机
  593. closePhoto(){
  594. this.photoPopup = false
  595. },
  596. getGoodsDetail(){
  597. let self = this
  598. this.$api.goodsDetail(this.goodsId).then(res => {
  599. self.goodsData = res.data.data;
  600. self.gradeId = self.goodsData.gradeId
  601. console.log(self.gradeId,698)
  602. self.getMenuList();
  603. self.getReMenuList() //获取重修目录
  604. if(self.goodsData.goodsPlayConfig){
  605. self.goodsPlayConfig = JSON.parse(self.goodsData.goodsPlayConfig);
  606. if(self.goodsPlayConfig.autoPlay>0){
  607. self.autoplay = true
  608. }
  609. if(self.goodsPlayConfig.drag>0){
  610. self.isAllowSeek = "yes"
  611. }
  612. if(self.goodsPlayConfig.speed>0){
  613. self.playbackRate = [0.5,0.8,1.0,1.25,1.5,2.0]
  614. }
  615. }
  616. if(self.goodsData.goodsPhotographConfig){
  617. self.goodsPhotographConfig = JSON.parse(self.goodsData.goodsPhotographConfig);
  618. if(self.goodsPhotographConfig.intervalTime){
  619. self.intervalTimeList = self.goodsPhotographConfig.intervalTime.split(',')
  620. }
  621. }
  622. })
  623. },
  624. startVideo() {
  625. this.startStatus = true;
  626. },
  627. getAnswerList() {
  628. let self = this;
  629. this.$api.answerList({ courseId: this.courseId }).then(res => {
  630. if (res.data.code == 200) {
  631. self.answerList = res.data.rows;
  632. }
  633. });
  634. },
  635. getReMenuList() {
  636. let self = this;
  637. this.$api.reMenuList({ courseId: this.courseId,rebuild:1,gradeId:this.gradeId }).then(res => {
  638. if (res.data.code == 200) {
  639. for (let i = 0; i < res.data.rows.length; i++) {
  640. let item = res.data.rows[i];
  641. item.down = true;
  642. item.id = item.menuId;
  643. item.name = item.menuName;
  644. }
  645. self.reMenuList = res.data.rows;
  646. }
  647. });
  648. },
  649. getMenuList() {
  650. let self = this;
  651. this.$api.reMenuList({ courseId: this.courseId,gradeId:this.gradeId }).then(res => {
  652. if (res.data.code == 200) {
  653. for (let i = 0; i < res.data.rows.length; i++) {
  654. let item = res.data.rows[i];
  655. item.down = true;
  656. item.id = item.menuId;
  657. item.name = item.menuName;
  658. }
  659. self.menuList = res.data.rows;
  660. }
  661. });
  662. },
  663. courseDetail() {
  664. let self = this;
  665. this.$api.courseDetail(this.courseId).then(res => {
  666. if (res.data.code == 200) {
  667. self.detail = res.data.data;
  668. self.gradeId = self.detail.gradeId
  669. }
  670. });
  671. },
  672. open(item) {
  673. item.showChildren = !item.showChildren;
  674. },
  675. change(index) {
  676. this.current = index;
  677. }
  678. }
  679. };
  680. </script>
  681. <style lang="scss" scope>
  682. .btnReply{
  683. width: 80rpx;
  684. height: 40rpx;
  685. background: #E3F0FF;
  686. border-radius: 16rpx;
  687. text-align: center;
  688. color: #007AFF;
  689. }
  690. .btnDel{
  691. width: 80rpx;
  692. height: 40rpx;
  693. background: #FFEDF0;
  694. border-radius: 16rpx;
  695. text-align: center;
  696. color: #FF2D55;
  697. }
  698. .btnReply{
  699. width: 80rpx;
  700. height: 40rpx;
  701. background: #E3F0FF;
  702. border-radius: 16rpx;
  703. font-size: 24rpx;
  704. }
  705. .photoBox{
  706. .photoTop{
  707. height: 74upx;
  708. display: flex;
  709. align-items: center;
  710. justify-content: space-between;
  711. padding: 0upx 38upx;
  712. .sqzz{
  713. width: 28upx;
  714. height: 28upx;
  715. display: flex;
  716. align-items: center;
  717. justify-content: center;
  718. }
  719. .centersq{
  720. color: #333;
  721. font-size: 30upx;
  722. font-weight: 500;
  723. }
  724. }
  725. .photoCenter{
  726. width: 750upx;
  727. height: 979upx;
  728. position: relative;
  729. .custom{
  730. width: 750upx;
  731. height: 979upx;
  732. position: absolute;
  733. top: 0;
  734. left: 0;
  735. image{
  736. width: 100%;
  737. height: 100%;
  738. }
  739. }
  740. }
  741. .btnResult{
  742. height: 100upx;
  743. width: 100%;
  744. background-color: #07c160;
  745. text-align: center;
  746. line-height: 100upx;
  747. color: #fff;
  748. font-size: 32upx;
  749. font-weight: bold;
  750. }
  751. }
  752. .chat_box {
  753. display: flex;
  754. padding: 20rpx;
  755. justify-content: space-between;
  756. }
  757. .chat3 {
  758. font-size: 30rpx;
  759. font-family: PingFang SC;
  760. font-weight: 500;
  761. color: #666666;
  762. margin-top: 10rpx;
  763. }
  764. .chat2 {
  765. font-size: 20rpx;
  766. font-family: PingFang SC;
  767. font-weight: 500;
  768. color: #999999;
  769. margin-top: 10rpx;
  770. }
  771. .chat1 {
  772. font-size: 24rpx;
  773. font-family: PingFang SC;
  774. font-weight: 500;
  775. color: #333333;
  776. }
  777. .leftPadding {
  778. margin-left: 8rpx;
  779. }
  780. .t2Content {
  781. font-size: 28rpx;
  782. font-family: PingFang SC;
  783. font-weight: bold;
  784. color: #999999;
  785. line-height: 48rpx;
  786. }
  787. .tBox2 {
  788. display: flex;
  789. padding-top: 10rpx;
  790. color: #333333;
  791. font-size: 30rpx;
  792. }
  793. .tBox {
  794. display: flex;
  795. align-items: center;
  796. padding-top: 10rpx;
  797. }
  798. .title {
  799. font-size: 24rpx;
  800. color: #999999;
  801. }
  802. page {
  803. padding-top: 10px;
  804. padding-top: constant(safe-area-inset-top);
  805. padding-top: env(safe-area-inset-top);
  806. }
  807. .inputBottom {
  808. position: fixed;
  809. left: 0;
  810. bottom: 0;
  811. background: #ffffff;
  812. height: 98rpx;
  813. display: flex;
  814. align-items: center;
  815. width: 100%;
  816. }
  817. .noteBox {
  818. width: 100%;
  819. background: #ffffff;
  820. padding: 10rpx;
  821. border-radius: 16rpx;
  822. }
  823. .dateBox {
  824. width: 216rpx;
  825. height: 48rpx;
  826. background: #ffffff;
  827. border-radius: 24rpx;
  828. font-size: 24rpx;
  829. color: #666666;
  830. text-align: center;
  831. line-height: 48rpx;
  832. margin: 20rpx 0;
  833. }
  834. .t_content1 {
  835. color: #007aff;
  836. margin-left: 10rpx;
  837. }
  838. .tag1 {
  839. border: 2rpx solid #007aff;
  840. border-radius: 8rpx;
  841. font-size: 20rpx;
  842. color: #007aff;
  843. padding: 5rpx;
  844. }
  845. .b_title {
  846. color: #333333;
  847. font-size: 30rpx;
  848. font-weight: bold;
  849. }
  850. page {
  851. background: #eaeef1;
  852. }
  853. .menuBox {
  854. width: 100%;
  855. background: #ffffff;
  856. border-radius: 16rpx;
  857. padding: 20rpx;
  858. margin-bottom: 20rpx;
  859. }
  860. .btnspric {
  861. border-top: 1rpx solid #eee;
  862. display: flex;
  863. align-items: center;
  864. justify-content: space-between;
  865. height: 108rpx;
  866. padding-left: 43rpx;
  867. padding-right: 32rpx;
  868. }
  869. .btnspric > .lefprL {
  870. font-size: 36rpx;
  871. color: #0c141f;
  872. font-weight: bold;
  873. }
  874. .btnspric > .lefprR {
  875. padding: 0rpx 24rpx;
  876. height: 60rpx;
  877. line-height: 60rpx;
  878. text-align: center;
  879. color: #fff;
  880. background: #32467b;
  881. border-radius: 24rpx;
  882. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  883. }
  884. .yhj,
  885. .hdyhj {
  886. padding: 24rpx 29rpx 24rpx 34rpx;
  887. }
  888. .yhj {
  889. border-bottom: 16rpx solid #f9f9f9;
  890. }
  891. .yhjtit {
  892. font-size: 30rpx;
  893. color: #0c141f;
  894. font-weight: 500;
  895. margin-bottom: 14rpx;
  896. }
  897. .yhjList {
  898. display: flex;
  899. align-items: center;
  900. justify-content: space-between;
  901. margin-bottom: 14rpx;
  902. }
  903. .yhjList > .yhjLefts {
  904. display: flex;
  905. align-items: center;
  906. }
  907. .yhjLefts > .yhl {
  908. color: #32467b;
  909. font-size: 30rpx;
  910. margin-right: 31rpx;
  911. }
  912. .yhjLefts > .yhbq {
  913. font-size: 24rpx;
  914. color: #ff9500;
  915. border-radius: 18rpx;
  916. background-color: rgba(255, 149, 0, 0.2);
  917. border: 2rpx solid #ff9500;
  918. height: 38rpx;
  919. line-height: 38rpx;
  920. padding: 0rpx 16rpx;
  921. }
  922. .ts {
  923. font-size: 24rpx;
  924. color: #999;
  925. margin: 14rpx 0rpx;
  926. padding-right: 29rpx;
  927. padding-left: 34rpx;
  928. }
  929. .yh {
  930. padding-top: 20rpx;
  931. }
  932. .yh > .yhtitle {
  933. display: flex;
  934. align-items: center;
  935. justify-content: space-between;
  936. padding-right: 29rpx;
  937. padding-left: 34rpx;
  938. }
  939. .priceBxs {
  940. display: flex;
  941. align-items: center;
  942. }
  943. .priceBxs > .pricleft {
  944. border-radius: 24rpx;
  945. border: 1rpx solid #e91313;
  946. background-color: rgba(233, 19, 19, 0.1);
  947. padding: 0rpx 18rpx;
  948. height: 49rpx;
  949. line-height: 49rpx;
  950. text-align: center;
  951. font-size: 30rpx;
  952. font-weight: 500;
  953. color: #e91313;
  954. margin-right: 13rpx;
  955. }
  956. .topBox {
  957. padding: 32rpx 32rpx 24rpx;
  958. border-bottom: 1rpx solid #eeeeee;
  959. }
  960. .topBox > .boldFonstType {
  961. font-weight: 500;
  962. font-size: 30rpx;
  963. margin: 16rpx 0rpx 23rpx;
  964. }
  965. .topBox > .firstTopL {
  966. display: flex;
  967. align-items: center;
  968. }
  969. .topBox > .firstTopL > .imageBs {
  970. width: 331rpx;
  971. height: 160rpx;
  972. border-radius: 6rpx;
  973. overflow: hidden;
  974. margin-right: 8rpx;
  975. box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(47, 67, 121, 0.08);
  976. }
  977. .topBox > .firstTopL > .imageBs > image {
  978. width: 100%;
  979. height: 100%;
  980. }
  981. .topBox > .firstTopL > .textBs {
  982. font-size: 30rpx;
  983. font-weight: bold;
  984. color: #0c141f;
  985. }
  986. .content {
  987. padding: 24rpx;
  988. text-align: left;
  989. }
  990. .catalogBox {
  991. display: flex;
  992. align-items: center;
  993. flex-wrap: nowrap;
  994. overflow-x: auto;
  995. padding-left: 38rpx;
  996. max-height: 305rpx;
  997. overflow-y: auto;
  998. transition: all 0.4s;
  999. }
  1000. .catalogBox > .catalogA {
  1001. min-width: 200rpx;
  1002. height: 48rpx;
  1003. line-height: 48rpx;
  1004. // text-align: center;
  1005. border: 2rpx solid transparent;
  1006. white-space: nowrap;
  1007. text-overflow: ellipsis;
  1008. overflow: hidden;
  1009. word-break: break-all;
  1010. border-radius: 10rpx;
  1011. background: rgba(22, 119, 255, 0.05);
  1012. padding-left: 19rpx;
  1013. box-sizing: border-box;
  1014. padding-right: 15rpx;
  1015. margin-right: 16rpx;
  1016. margin-bottom: 20rpx;
  1017. margin-top: 15rpx;
  1018. font-size: 24rpx;
  1019. color: #666;
  1020. }
  1021. .catalogBox > .activesq {
  1022. border-color: #1677ff;
  1023. }
  1024. .changeCatalogBox {
  1025. display: block;
  1026. }
  1027. .catalogBox::-webkit-scrollbar {
  1028. display: none; /* Chrome Safari */
  1029. }
  1030. .box {
  1031. position: relative;
  1032. top: 650rpx;
  1033. padding-bottom: 88rpx;
  1034. margin: 20rpx;
  1035. }
  1036. .price_t2 {
  1037. font-size: 18rpx;
  1038. font-family: PingFang SC;
  1039. font-weight: 500;
  1040. text-decoration: line-through;
  1041. color: #999999;
  1042. }
  1043. .price_t1 {
  1044. font-size: 33rpx;
  1045. font-family: PingFang SC;
  1046. font-weight: bold;
  1047. color: #e91313;
  1048. }
  1049. .sc_t {
  1050. font-size: 22rpx;
  1051. color: #000000;
  1052. }
  1053. .sc {
  1054. width: 29rpx;
  1055. height: 29rpx;
  1056. }
  1057. .buy {
  1058. width: 138rpx;
  1059. height: 48rpx;
  1060. line-height: 48rpx;
  1061. background: #32467b;
  1062. border-radius: 10rpx;
  1063. color: #ffffff;
  1064. font-size: 28rpx;
  1065. text-align: center;
  1066. vertical-align: middle;
  1067. position: absolute;
  1068. right: 30rpx;
  1069. }
  1070. .video_body {
  1071. padding-bottom: 96rpx;
  1072. }
  1073. .footer_tab {
  1074. position: fixed;
  1075. bottom: 0;
  1076. height: 96rpx;
  1077. width: 100%;
  1078. background-color: #ffffff;
  1079. }
  1080. .tj_box {
  1081. width: 50%;
  1082. display: inline-block;
  1083. text-align: center;
  1084. margin: 10rpx 0;
  1085. }
  1086. .teacher_t {
  1087. font-size: 24rpx;
  1088. font-family: PingFang SC;
  1089. font-weight: 400;
  1090. color: #666666;
  1091. line-height: 36rpx;
  1092. margin-left: 15rpx;
  1093. }
  1094. .teacher_img {
  1095. width: 87rpx;
  1096. height: 129rpx;
  1097. }
  1098. .t2 {
  1099. font-size: 24rpx;
  1100. font-family: PingFang SC;
  1101. color: #666666;
  1102. line-height: 36rpx;
  1103. margin: 15rpx;
  1104. }
  1105. .r_t2 {
  1106. width: 201rpx;
  1107. height: 49rpx;
  1108. background: rgba(22, 119, 255, 0.05);
  1109. border: 1rpx solid #32467b;
  1110. border-radius: 16rpx;
  1111. color: #666666;
  1112. font-size: 23rpx;
  1113. text-align: center;
  1114. display: flex;
  1115. align-items: center;
  1116. padding: 5rpx;
  1117. }
  1118. .scroll_box {
  1119. width: 100%;
  1120. height: 60rpx;
  1121. background: #ffffff;
  1122. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  1123. white-space: nowrap;
  1124. overflow: hidden;
  1125. margin: 15rpx 0;
  1126. }
  1127. .r_sliper {
  1128. padding: 0 20rpx;
  1129. }
  1130. .top_line {
  1131. width: 6rpx;
  1132. height: 22rpx;
  1133. background: #32467b;
  1134. margin-right: 10rpx;
  1135. }
  1136. .video_t2 {
  1137. font-size: 24rpx;
  1138. font-family: PingFang SC;
  1139. font-weight: 500;
  1140. color: #666666;
  1141. }
  1142. .video_t1 {
  1143. height: 80rpx;
  1144. color: #333333;
  1145. line-height: 80rpx;
  1146. font-size: 30rpx;
  1147. font-family: PingFang SC;
  1148. font-weight: bold;
  1149. color: #333333;
  1150. overflow: hidden;
  1151. text-overflow:ellipsis;
  1152. white-space: nowrap;
  1153. }
  1154. .video_t1_t {
  1155. display: flex;
  1156. flex-direction: column;
  1157. height: 80rpx;
  1158. color: #333333;
  1159. text-align: center;
  1160. align-items: center;
  1161. border-left: solid 1px #d6d6db;
  1162. }
  1163. .video_play {
  1164. position: absolute;
  1165. width: 95rpx;
  1166. height: 95rpx;
  1167. top: 0;
  1168. left: 0;
  1169. right: 0;
  1170. bottom: 0;
  1171. margin: auto;
  1172. }
  1173. .video_box {
  1174. position: relative;
  1175. }
  1176. .rotoct {
  1177. transform: rotate(90deg);
  1178. }
  1179. </style>