detail.vue 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128
  1. <template>
  2. <view>
  3. <nav-bar title="身份证"></nav-bar>
  4. <view style="position: fixed;width: 100%;z-index: 999;background: #FFFFFF;" id="top">
  5. <view class="video_box" v-if="!startStatus">
  6. <image :src="$method.splitImgHost(detail.coverUrl)" style="width: 100%;height: 460rpx;"></image>
  7. <image v-if="false" class="video_play" src="/static/play.png" @click="startVideo"></image>
  8. </view>
  9. <view v-else>
  10. <view class="video_box" style="width: 100%;height: 460rpx;" v-if="playVID">
  11. <polyv-player
  12. id="playerVideo"
  13. playerId="playerVideo"
  14. height="460rpx"
  15. :vid="vid"
  16. :showSettingBtn="true"
  17. :enablePlayGesture="true"
  18. @statechange="onStateChange"
  19. :autoplay="autoplay"
  20. :isAllowSeek="isAllowSeek"
  21. :playbackRate="playbackRate"
  22. :startTime="startTime"
  23. ></polyv-player>
  24. </view>
  25. <view class="video_box" style="width: 100%;height: 460rpx;" v-if="playChannelId>0">
  26. <player
  27. class="plv-mp-demo-player"
  28. :videoOption="videoOption"
  29. @onLiveStatusChange="playerLiveStatusChange"
  30. />
  31. </view>
  32. </view>
  33. <view>
  34. <u-row>
  35. <u-col span="10">
  36. <view class="video_t1">{{ detail.courseName }}</view>
  37. </u-col>
  38. <u-col span="2" v-if="false">
  39. <view class="video_t1_t" @click="openJY">
  40. <image src="/static/icon/jy_icon.png" style="width: 40rpx;height: 40rpx;"></image>
  41. 讲义
  42. </view>
  43. </u-col>
  44. </u-row>
  45. </view>
  46. <u-line color="#D6D6DB" />
  47. <view>
  48. <view><u-tabs gutter="0" :item-width="itemWidth()" :list="list" font-size="32" bar-width="24" :current="current" @change="change" active-color="#007AFF"></u-tabs></view>
  49. </view>
  50. <u-line color="#D6D6DB" />
  51. </view>
  52. <view class="box">
  53. <!--目录 -->
  54. <view v-show="current == 0">
  55. <view class="menuBox" v-for="(item, index) in menuList" :key="index">
  56. <!--模块 -->
  57. <view v-if="item.type == 1"><courseModule :courseId="courseId" :learningOrder="businessData.goodsLearningOrder" :goodsId="goodsId" :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="item.menuId"></courseModule></view>
  58. <!--章 -->
  59. <view v-if="item.type == 2"><courseChapter :courseId="courseId" @playEnd="sectionPlayEnd($event,index)" :learningOrder="businessData.goodsLearningOrder" :goodsId="goodsId" :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="'0-' + item.menuId"></courseChapter></view>
  60. <!--节 -->
  61. <view v-if="item.type == 3"><courseSection @playEnd="sectionPlayEnd($event,index)" :courseId="courseId" :goodsId="goodsId" :gradeId="gradeId" :isBuy="true" :menuItem="item" :levelId="'0-0-' + item.menuId"></courseSection></view>
  62. </view>
  63. </view>
  64. <!--讲义 -->
  65. <view v-show="current == 1">
  66. <view class="lecture-box" v-if="courseHandoutsData">
  67. <view class="title">
  68. {{courseHandoutsData.handoutsName}}
  69. <!-- 这是后台配置的讲义标题过长省略这是后台配置的讲义标题过长省略 -->
  70. </view>
  71. <view class="btn" @click="openDocument">
  72. <u-icon name="download" color="#007AFF" size="40"></u-icon>
  73. </view>
  74. </view>
  75. <view style="text-align: center;" v-else>暂无讲义</view>
  76. <!-- <view class="lecture-content">
  77. <rich-text :nodes="'讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容讲义内容'"></rich-text>
  78. </view> -->
  79. <!-- <view class="inputBottom">
  80. <view style="width: 10%;"><image src="/static/icon/note3.png" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image></view>
  81. <view style="width: 73%;height: 100%;padding: 10rpx 0;">
  82. <u-input class="input" height="60" fixed="true" placeholder="您可以在这里输入笔记内容" type="textarea" :custom-style="inputStyle" v-model="noteValue" />
  83. </view>
  84. <view style="color: #007AFF;font-size: 30rpx;font-weight: bold;width: 15%;text-align: center;" @click="postNote">提交</view>
  85. </view> -->
  86. </view>
  87. <!--笔记 -->
  88. <view v-show="current == 2">
  89. <view v-if="noteList.length == 0" style="text-align: center;">暂无笔记</view>
  90. <view class="inputBottom">
  91. <view style="width: 10%;"><image src="/static/icon/note3.png" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image></view>
  92. <view style="width: 73%;height: 100%;padding: 10rpx 0;">
  93. <u-input class="input" height="60" fixed="true" placeholder="您可以在这里输入笔记内容" type="textarea" :custom-style="inputStyle" v-model="noteValue" />
  94. </view>
  95. <view style="color: #007AFF;font-size: 30rpx;font-weight: bold;width: 15%;text-align: center;" @click="postNote">提交</view>
  96. </view>
  97. <view v-for="(item, index) in noteList" :key="index">
  98. <view class="dateBox">{{ $method.timestampToTime(item.dateNote) }}</view>
  99. <view class="noteBox">
  100. <view v-for="(item1, index1) in item.userNotes" :key="index1" style="margin-top: 30rpx;" @click="jumpNote(item1)">
  101. <view style="display: flex;">
  102. <view>
  103. <view>
  104. <image src="/static/icon/note2.png" v-if="noteId != item1.noteId" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image>
  105. <image src="/static/icon/note1.png" v-if="noteId == item1.noteId" style="width: 39rpx;height: 39rpx;margin:0 29rpx;"></image>
  106. </view>
  107. <view class="title" style="width: 39rpx;height: 39rpx;margin:0 29rpx;">{{ $method.secondToDate(item1.noteSecond) }}</view>
  108. </view>
  109. <view style="margin-left: 10rpx;">
  110. <view class="t2Content leftPadding">{{ item1.sectionName }}</view>
  111. <view class="tBox2">{{ item1.noteText }}</view>
  112. </view>
  113. </view>
  114. </view>
  115. </view>
  116. </view>
  117. </view>
  118. <!--答疑 -->
  119. <view v-show="current == 3">
  120. <view class="inputBottom">
  121. <view class="flex_auto">
  122. <u-input height="60" fixed="true" :placeholder="placeholder" type="textarea" :custom-style="inputStyle" v-model="ctxValue" />
  123. </view>
  124. <view class="btn" @click="postContent">提交</view>
  125. </view>
  126. <view v-for="(item, index) in answerList" :key="index" style="background-color: #FFFFFF;margin-bottom: 20rpx;">
  127. <view class="chat_box" @click.stop="clearCtx">
  128. <view style="display: flex;">
  129. <view><image :src="item.assignUserId > 0 ? '/static/logo_xcx.png' :$method.splitImgHost(item.avatar)" style="width: 64rpx;height: 64rpx;"></image></view>
  130. <view style="margin-left: 15rpx;">
  131. <view class="chat1">{{ item.assignUserId > 0 ? '祥粤老师' : item.realname }}</view>
  132. <view class="chat2">{{ $method.timestampToTime(item.createTime,false) }}</view>
  133. <view class="chat3">
  134. <text v-if="item.assignUserId > 0">回复</text>
  135. <text v-if="item.assignUserId > 0" style="color: #007AFF;">@{{ item.assignRealname }}</text>
  136. {{ item.answerText }}
  137. </view>
  138. </view>
  139. </view>
  140. <view class="btnReply" @click.stop="replyContent(item)" v-if="item.userId != userInfo.userId">回复</view>
  141. <view v-else class="btnDel" @click.stop="delContent(item)">删除</view>
  142. </view>
  143. <u-line color="#D6D6DB" />
  144. </view>
  145. <view v-if="answerList.length == 0" style="text-align: center;">暂无记录</view>
  146. </view>
  147. <!--目录 -->
  148. <view v-show="current == 4" >
  149. <view class="menuBox" v-for="(item, index) in reMenuList" :key="index">
  150. <!--模块 -->
  151. <view v-if="item.type == 1"><courseModule :courseId="courseId" :goodsId="goodsId" :gradeId="gradeId" :isRebuild="true" :isBuy="true" :menuItem="item" :levelId="item.menuId"></courseModule></view>
  152. <!--章 -->
  153. <view v-if="item.type == 2">
  154. <courseChapter :courseId="courseId" @playEnd="sectionPlayEnd($event,index)" :gradeId="gradeId" :goodsId="goodsId" :isRebuild="true" :isBuy="true" :menuItem="item" :levelId="'0-' + item.menuId"></courseChapter>
  155. </view>
  156. <!--节 -->
  157. <view v-if="item.type == 3">
  158. <courseSection :courseId="courseId" @playEnd="sectionPlayEnd($event,index)" :gradeId="gradeId" :goodsId="goodsId" :isRebuild="true" :isBuy="true" :nextMenuItem="findMenuNextSection(index)" :menuItem="item" :levelId="'0-0-' + item.menuId"></courseSection>
  159. </view>
  160. </view>
  161. </view>
  162. </view>
  163. <!-- 播放前拍照end -->
  164. <u-popup v-model="showSet" :mask-close-able="false" mode="center" border-radius="24">
  165. <view style="align-items:center;padding: 0 40rpx;display: flex;flex-direction: column;justify-content:center;">
  166. <view style="font-weight: bold;color: #333333;font-size: 30rpx;margin-top: 30rpx;">温馨提示</view>
  167. <view style="width: 457rpx;color: #666666;font-size: 30rpx;margin-top: 30rpx;">学习过程中需要拍照验证学员身份,
  168. 拍照功能需要使用您的相机。
  169. 是否授权使用?</view>
  170. <view style="margin: 40rpx 0;">
  171. <button open-type="openSetting" @bindopensetting="openSetting" class="btnSet">去授权</button>
  172. </view>
  173. </view>
  174. </u-popup>
  175. <u-mask :show="photoPopup" >
  176. <!-- 播放前拍照start -->
  177. <view v-if="photoPopup" :mask-close-able="false" style="bottom: 0;position: fixed;width: 100%;z-index: 999;">
  178. <view class="photoBox">
  179. <view class="photoTop">
  180. <view class="sqzz" v-if="false"><u-icon name="close" color="#333333" size="30" @click="closePhoto"></u-icon></view>
  181. <view class="centersq">请正视手机屏幕</view>
  182. <view class="sqzz"></view>
  183. </view>
  184. <view class="photoCenter">
  185. <view style="width: 100%; height: 979rpx;position: fixed;" v-if="photoPopup">
  186. <camera device-position="front" flash="off" @error="error" style="width: 100%; height: 100%;" ></camera>
  187. </view>
  188. <view class="custom"><image src="/static/zhezhao.png" mode=""></image></view>
  189. </view>
  190. <view class="btnResult" @click="takePhoto">拍照</view>
  191. </view>
  192. </view>
  193. </u-mask>
  194. </view>
  195. </template>
  196. <script>
  197. import plv from '../static/polyv-sdk/index';
  198. import courseModule from '@/components/course/courseModule.vue';
  199. import courseChapter from '@/components/course/courseChapter.vue';
  200. import courseSection from '@/components/course/courseSection.vue';
  201. import { mapGetters } from 'vuex';
  202. export default {
  203. components: {
  204. courseModule,
  205. courseChapter,
  206. courseSection
  207. },
  208. data() {
  209. return {
  210. initLiveOk:false,
  211. livePlay:false, //是否正在播放直播,不含暂停
  212. liveDuration:0, //直播观看时长
  213. videoOption:{
  214. mode: 'live',
  215. uid: '',
  216. cid: '',
  217. openId: '',
  218. isAutoChange: false,
  219. forceVideo: false,
  220. },
  221. courseHandoutsData:'',
  222. liveDetail:{},
  223. showSet:false,
  224. startStatus: false,
  225. detail: {},
  226. courseId: 0,
  227. placeholder: '您可以在这里输入笔记内容\n还可以点击左侧图标为笔记加上时间标记',
  228. inputStyle: {
  229. background: 'rgba(244, 244, 244, 0.98)',
  230. borderRadius: '24rpx',
  231. padding: '8rpx',
  232. marginBottom: '10rpx'
  233. },
  234. list: [],
  235. menuList: [],
  236. current: 0,
  237. vid: '',
  238. goodsId: 0,
  239. goodsData: {},
  240. photoPopup: false,
  241. goodsPlayConfig: null,
  242. autoplay: false,
  243. isAllowSeek: 'no',
  244. playbackRate: [1.0],
  245. timer: null,
  246. goodsPhotographConfig: null,
  247. intervalTimeList: [], // 间隔拍照时长
  248. intervalTimeIndex: 0, //当前处于哪个时间段拍照
  249. playTime: 0, //页面播放时长,不含暂停
  250. currentTime: 0,
  251. avatarUrl: '',
  252. ossAvatarUrl: '',
  253. studyDuration: 0, // 当前视频时长
  254. gradeId: 0,
  255. chapterId: 0,
  256. moduleId: 0,
  257. reMenuList: [],
  258. answerList: [],
  259. assignUserId: 0,
  260. placeholder: '您可以在这里输入答疑内容',
  261. ctxValue: '',
  262. noteList: [],
  263. noteValue: '',
  264. noteId: 0,
  265. recordObj: 0,
  266. gradeDetail:{},
  267. needSeek: false, //第一次播放是否需要跳转
  268. needProfileModal:false, //是否需要资料审核弹框
  269. liveObj:{},
  270. photoNum:0,
  271. photoList:[], //拍照的时间点
  272. photoConfig:false, //是否配置好拍照次数
  273. photoIndex:0, //当前位于拍照的区间下标 从0开始
  274. photoHistoryList:[], //已拍照历史的下标点
  275. businessData:{},
  276. isRebuild:false, //视频是否从重修目录点击
  277. };
  278. },
  279. computed: { ...mapGetters(['userInfo', 'playSectionId','playChannelId','playVID']) },
  280. onLoad(option) {
  281. this.courseId = Number(option.id);
  282. this.goodsId = Number(option.goodsId);
  283. this.courseDetail();
  284. this.getGoodsDetail();
  285. this.getAnswerList();
  286. let noteSecond = Number(option.noteSecond);
  287. if(noteSecond>0){
  288. //我的消息跳过来,播放节
  289. let item = {
  290. sectionId:Number(option.sectionId),
  291. recordingUrl:option.recordingUrl,
  292. noteSecond:noteSecond,
  293. studyDuration:noteSecond
  294. }
  295. this.$store.commit('setPlaySectionId', {playSectionId :item.sectionId});
  296. this.$store.commit('setPlayVID', {playVID :item.recordingUrl});
  297. this.playNoteVideo(item);
  298. }
  299. },
  300. onShow() {
  301. var self = this;
  302. //相机授权
  303. this.getCameraSetting()
  304. this.$api.getbaseprofiletplists({ goodsId: self.goodsId }).then(res => {
  305. console.log(res,'res')
  306. if (res.data.code === 200 && res.data.rows.length) {
  307. if (res.data.rows[0].keyValue) {
  308. self.$api.getbaseprofiletpgetInfo({ goodsId: self.goodsId }).then(result => {
  309. console.log(result,'result')
  310. if (result.data.code === 200) {
  311. if (!result.data.data || (result.data.data.status === 3 && result.data.data.changeStatus === 1)) {
  312. if (!result.data.data) {
  313. self.needProfileModal = true
  314. uni.showModal({
  315. content: '请前往填写资料',
  316. cancelText: '返回',
  317. success: function(resultst) {
  318. if (resultst.confirm) {
  319. self.$navTo.togo('/pages2/verify/input', {
  320. id: self.goodsId
  321. });
  322. }
  323. if (resultst.cancel) {
  324. uni.navigateBack();
  325. }
  326. }
  327. });
  328. } else {
  329. self.needProfileModal = true
  330. uni.showModal({
  331. content: '资料审核不通过,请前往重新填写',
  332. cancelText: '返回',
  333. success: function(resultst) {
  334. if (resultst.confirm) {
  335. self.$navTo.togo('/pages2/verify/input', {
  336. id: self.goodsId
  337. });
  338. }
  339. if (resultst.cancel) {
  340. uni.navigateBack();
  341. }
  342. }
  343. });
  344. }
  345. } else if (result.data.data.status === 1 && JSON.parse(res.data.rows[0].keyValue2)[0]) {
  346. self.$api.getbaseprofileStampgetInfo({ goodsId: self.goodsId }).then(k => {
  347. if (k.data.code === 200) {
  348. if (!k.data.data || (k.data.data.status === 3 && k.data.data.changeStatus === 1)) {
  349. if (!k.data.data) {
  350. self.needProfileModal = true
  351. uni.showModal({
  352. cancelText: '返回',
  353. content: '请前往填写盖章资料',
  354. success: function(resultst) {
  355. if (resultst.confirm) {
  356. self.$navTo.togo('/pages2/verify/input2', {
  357. id: self.goodsId
  358. });
  359. }
  360. if (resultst.cancel) {
  361. uni.navigateBack();
  362. }
  363. }
  364. });
  365. } else {
  366. self.needProfileModal = true
  367. uni.showModal({
  368. cancelText: '返回',
  369. content: '资料盖章审核不通过,请前往重新填写',
  370. success: function(resultst) {
  371. if (resultst.confirm) {
  372. self.$navTo.togo('/pages2/verify/input2', {
  373. id: self.goodsId
  374. });
  375. }
  376. if (resultst.cancel) {
  377. uni.navigateBack();
  378. }
  379. }
  380. });
  381. }
  382. }
  383. }
  384. });
  385. }
  386. }
  387. });
  388. }
  389. }
  390. });
  391. console.log(this.gradeId,7512)
  392. if(this.gradeId>0){
  393. //提交完资料返回判断是否已开班
  394. this.getGradeInfo()
  395. }
  396. },
  397. onUnload() {
  398. if (this.playSectionId > 0) {
  399. //退出提交记录
  400. this.postStudyRecord();
  401. }
  402. //清除正在播放的节ID
  403. this.$store.commit('setPlaySectionId', { playSectionId: 0 });
  404. this.$store.commit('setPlayChannelId', { playChannelId: 0 });
  405. this.$store.commit('setPlayVID', { playVID: null });
  406. this.closePlv()
  407. console.log('onUnload')
  408. //移除所有的事件监听器
  409. uni.$off();
  410. if (this.timer) {
  411. clearInterval(this.timer);
  412. }
  413. },
  414. mounted() {
  415. uni.$on('changeSection', oldSectionId => {
  416. console.log(this.playVID)
  417. this.photoConfig = false
  418. this.photoIndex = 0
  419. var polyvPlayerContext = this.selectComponent('#playerVideo');
  420. if(polyvPlayerContext){
  421. //解决同个节视频切换问题
  422. polyvPlayerContext.pause();
  423. }
  424. //清除直播
  425. this.$store.commit('setPlayChannelId', { playChannelId: 0 });
  426. this.postStudyRecord(0, oldSectionId);
  427. });
  428. uni.$on('getSection', item => {
  429. //清除直播
  430. this.photoConfig = false
  431. this.photoIndex = 0
  432. this.$store.commit('setPlayChannelId', { playChannelId: 0 });
  433. //获取拍照历史
  434. this.getPhotoLastRecord()
  435. this.playVideo(item);
  436. });
  437. uni.$on('levelId', item => {
  438. let arr = item.split('-');
  439. //点击节获取的各层级ID
  440. this.moduleId = arr[0];
  441. this.chapterId = arr[1];
  442. });
  443. uni.$on('getChannel', item => {
  444. //清除录播
  445. this.$store.commit('setPlayVID', {playVID :null});
  446. this.playChannel(item);
  447. });
  448. uni.$on('isRebuild',item => {
  449. console.log(item)
  450. this.isRebuild = item;
  451. })
  452. },
  453. methods: {
  454. /**
  455. * 模块大节播放完毕,刷新列表
  456. */
  457. sectionPlayEnd(isRebuild,index) {
  458. console.log('sectionPlayEnd')
  459. console.log('isRebuild',isRebuild),
  460. console.log('index',index)
  461. if(this.reMenuList.length>0) { //有重修目录
  462. if(isRebuild.isRebuild) { //从重修点击
  463. this.$api.reMenuList({ courseId: this.courseId, rebuild: 1, gradeId: this.gradeId }).then(res => {
  464. console.log('Rebuild1')
  465. if (res.data.code == 200) {
  466. if(res.data.rows.length) {
  467. // res.data.rows[index].name = res.data.rows[index].menuName;
  468. // this.$set(this.reMenuList,index,res.data.rows[index])
  469. for (let i = 0; i < res.data.rows.length; i++) {
  470. let item = res.data.rows[i];
  471. item.down = true;
  472. item.id = item.menuId;
  473. item.name = item.menuName;
  474. }
  475. this.reMenuList = []
  476. this.$nextTick(() => {
  477. this.reMenuList = res.data.rows;
  478. console.log(this.reMenuList)
  479. })
  480. } else {
  481. this.reMenuList = []
  482. }
  483. this.$nextTick(() => {
  484. if(this.reMenuList.length>0){
  485. this.list = [
  486. {
  487. name: '目录'
  488. },
  489. {
  490. name: '讲义'
  491. },
  492. {
  493. name: '笔记'
  494. },
  495. {
  496. name: '答疑'
  497. },
  498. {name:'重修目录'}
  499. ];
  500. } else {
  501. this.list = [
  502. {
  503. name: '目录'
  504. },
  505. {
  506. name: '讲义'
  507. },
  508. {
  509. name: '笔记'
  510. },
  511. {
  512. name: '答疑'
  513. }
  514. ];
  515. if(this.current == 4) {
  516. this.current = 0;
  517. }
  518. }
  519. })
  520. }
  521. });
  522. this.$api.reMenuList({ courseId: this.courseId, gradeId: this.gradeId }).then(res => {
  523. console.log('noRebuild1')
  524. if (res.data.code == 200) {
  525. for (let i = 0; i < res.data.rows.length; i++) {
  526. let item = res.data.rows[i];
  527. item.down = true;
  528. item.id = item.menuId;
  529. item.name = item.menuName;
  530. }
  531. this.menuList = []
  532. this.$nextTick(() => {
  533. this.menuList = res.data.rows;
  534. })
  535. }
  536. });
  537. } else { //从普通目录点击
  538. this.$api.reMenuList({ courseId: this.courseId, gradeId: this.gradeId }).then(res => {
  539. console.log('noRebuild2')
  540. if (res.data.code == 200) {
  541. res.data.rows[index].name = res.data.rows[index].menuName;
  542. res.data.rows[index].id = res.data.rows[index].menuId;
  543. this.$set(this.menuList,index,res.data.rows[index])
  544. }
  545. });
  546. this.$api.reMenuList({ courseId: this.courseId, rebuild: 1, gradeId: this.gradeId }).then(res => {
  547. console.log('Rebuild2')
  548. if (res.data.code == 200) {
  549. for (let i = 0; i < res.data.rows.length; i++) {
  550. let item = res.data.rows[i];
  551. item.down = true;
  552. item.id = item.menuId;
  553. item.name = item.menuName;
  554. }
  555. this.reMenuList = []
  556. this.$nextTick(() => {
  557. this.reMenuList = res.data.rows;
  558. if(this.reMenuList.length>0){
  559. this.list = [
  560. {
  561. name: '目录'
  562. },
  563. {
  564. name: '讲义'
  565. },
  566. {
  567. name: '笔记'
  568. },
  569. {
  570. name: '答疑'
  571. },
  572. {name:'重修目录'}
  573. ];
  574. } else {
  575. this.list = [
  576. {
  577. name: '目录'
  578. },
  579. {
  580. name: '讲义'
  581. },
  582. {
  583. name: '笔记'
  584. },
  585. {
  586. name: '答疑'
  587. }
  588. ];
  589. if(this.current == 4) {
  590. this.current = 0;
  591. }
  592. }
  593. })
  594. }
  595. });
  596. }
  597. } else { //没有重修目录
  598. this.$api.reMenuList({ courseId: this.courseId, gradeId: this.gradeId }).then(res => {
  599. console.log('noRebuild3')
  600. console.log('noRebuild3index',index)
  601. if (res.data.code == 200) {
  602. res.data.rows[index].name = res.data.rows[index].menuName;
  603. res.data.rows[index].id = res.data.rows[index].menuId;
  604. this.$set(this.menuList,index,res.data.rows[index])
  605. }
  606. });
  607. }
  608. },
  609. /**
  610. * 获取业务层次详情
  611. */
  612. courseBusiness(){
  613. this.$api.courseBusiness(this.goodsData.businessId).then(res => {
  614. this.businessData = res.data.data;
  615. })
  616. },
  617. /**
  618. * 计算tabs宽度
  619. */
  620. itemWidth() {
  621. return 100/this.list.length + '%'
  622. },
  623. /**
  624. * 获取讲义权限
  625. */
  626. courseHandouts() {
  627. this.$api.courseHandouts(this.goodsData.handoutsId).then(res => {
  628. this.courseHandoutsData = res.data.data
  629. })
  630. },
  631. findMenuNextSection(index){
  632. for(let i=index+1;i<this.reMenuList.length;i++){
  633. let item = this.reMenuList[i]
  634. if(item.type==3){
  635. return item;
  636. }
  637. }
  638. return {}
  639. },
  640. getPhotoLastRecord() {
  641. let self = this;
  642. let data = {
  643. sectionId: parseInt(self.playSectionId),
  644. goodsId: parseInt(self.goodsId),
  645. courseId: parseInt(self.courseId),
  646. gradeId: parseInt(self.gradeId),
  647. chapterId: parseInt(self.chapterId),
  648. moduleId: parseInt(self.moduleId)}
  649. this.$api.getPhotoLastRecord(data).then(res => {
  650. if(res.data.code==200){
  651. //清空历史数据
  652. self.photoHistoryList = []
  653. this.photoIndex = 0
  654. self.photoList = []
  655. for(let i=0;i<res.data.data.length;i++){
  656. //-2存储随机拍照数组
  657. if(res.data.data[i].photoIndex==-2){
  658. self.photoList = res.data.data[i].timeInterval.split(',')
  659. }else{
  660. self.photoHistoryList.push(res.data.data[i].photoIndex)
  661. }
  662. }
  663. }
  664. });
  665. },
  666. //postTime 只提交随机时间
  667. postCoursePhotoRecord(postTime=false) {
  668. let currentTime = 0;
  669. var polyvPlayerContext = this.selectComponent('#playerVideo');
  670. if (polyvPlayerContext) {
  671. currentTime = polyvPlayerContext.getCurrentTime();
  672. }
  673. let self = this;
  674. let photoIndex = self.photoIndex
  675. let data = {
  676. photo: self.ossAvatarUrl,
  677. sectionId: parseInt(self.playSectionId),
  678. goodsId: parseInt(self.goodsId),
  679. courseId: parseInt(self.courseId),
  680. photoTime: parseInt(currentTime > 0 ? currentTime : 0),
  681. gradeId: parseInt(self.gradeId),
  682. photoIndex: postTime?-2:parseInt(photoIndex),//从0算起,-2只提交随机时间
  683. photoNum:parseInt(self.photoNum),
  684. chapterId: parseInt(self.chapterId),
  685. moduleId: parseInt(self.moduleId),
  686. timeInterval: postTime?self.photoList.join(','):''
  687. };
  688. console.log('提交接口', data);
  689. this.$api.coursePhotoRecord(data).then(res => {
  690. console.log(res);
  691. });
  692. },
  693. randomNum(minNum,maxNum){
  694. switch(arguments.length){
  695. case 1:
  696. return parseInt(Math.random()*minNum+1,10);
  697. break;
  698. case 2:
  699. return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
  700. break;
  701. default:
  702. return 0;
  703. break;
  704. }
  705. },
  706. //配置随机拍照时间
  707. configPhoto(){
  708. var polyvPlayerContext = this.selectComponent('#playerVideo');
  709. let totalVideoTime = polyvPlayerContext.getDuration()
  710. let duration = polyvPlayerContext.getCurrentTime()
  711. let photoNum = this.photoNum
  712. if(!this.photoConfig){
  713. this.photoConfig = true
  714. let spaceTime = Math.floor(totalVideoTime/photoNum) //拍照时间区间
  715. if(spaceTime<5){//区间小于5秒
  716. photoNum = Math.floor(totalVideoTime/5)
  717. spaceTime = 5
  718. }
  719. if(photoNum<1){
  720. photoNum = 1 //只要设置,至少拍一次
  721. spaceTime = totalVideoTime
  722. }
  723. let initSpace = 0
  724. //没有历史拍照间隔数据
  725. if(this.photoList.length==0){
  726. for(let i=0;i<photoNum;i++){
  727. let s = this.randomNum(initSpace,initSpace+spaceTime)
  728. if(s>totalVideoTime){
  729. s = totalVideoTime-1
  730. }
  731. if(s<=5){
  732. s =5 //避免出现5秒内拍照时间
  733. }
  734. this.photoList.push(s)
  735. initSpace+=spaceTime
  736. }
  737. console.log(this.photoList,"随机拍照时间数组11",photoNum,initSpace,spaceTime)
  738. this.postCoursePhotoRecord(true)//提交随机拍照时间数组
  739. }
  740. console.log(this.photoList,"随机拍照时间数组")
  741. //兼容已有观看历史
  742. for(let i=0;i<this.photoList.length-1;i++){
  743. if(this.photoList[i]<duration&&this.photoList[i+1]>duration){
  744. this.photoIndex = i+1
  745. // console.log("我的修改了photoIndex")
  746. break
  747. }
  748. if(duration>this.photoList[this.photoList.length-1]){
  749. this.photoIndex = this.photoList.length-1 //取最后一个下标
  750. // console.log("我的修改了photoIndex")
  751. break
  752. }
  753. }
  754. }
  755. },
  756. getLiveUid(channelId) {
  757. let self = this;
  758. return new Promise(resolve => {
  759. let data = {
  760. channelId: channelId
  761. };
  762. self.$api.polyvSign(data).then(res => {
  763. resolve(res.data.data);
  764. });
  765. });
  766. },
  767. timeEventLiving() {
  768. if (plv != null) {
  769. if(this.livePlay){
  770. this.liveDuration = this.liveDuration +1 //每隔1秒
  771. if(this.liveDuration==2){ //直播第2秒拍照
  772. if(this.goodsPhotographConfig){
  773. if(this.goodsPhotographConfig.livephotograph==1){
  774. //开启直播拍照
  775. this.openPhoto();
  776. }
  777. }
  778. }
  779. }
  780. }
  781. },
  782. playerLiveStatusChange(e) {
  783. const status = e.detail.status;
  784. console.log('直播状态',status);
  785. if (status === 'live') {
  786. console.log('开始直播');
  787. //开始播放
  788. if (this.timer) {
  789. clearInterval(this.timer);
  790. }
  791. this.livePlay = true
  792. this.timer = setInterval(this.timeEventLiving, 1000); //定时器
  793. }
  794. if (status === 'end') {
  795. if(this.livePlay){
  796. //只有播放过的结束才提交,避免未开播触发结束
  797. this.postStudyRecord(1);
  798. }
  799. console.log('结束直播');
  800. this.livePlay = false
  801. // 未开始
  802. }
  803. },
  804. closePlv(){
  805. if(plv){
  806. plv.destroy();
  807. }
  808. },
  809. playChannel(item){
  810. if (this.timer) {
  811. clearInterval(this.timer);
  812. }
  813. this.startStatus = true
  814. this.initLive()
  815. },
  816. setLiveOption(status) {
  817. const { userId, channelId, recordFileSimpleModel, playbackEnabled } = this.detail;
  818. const playRecordFile = playbackEnabled && recordFileSimpleModel && status === 'end';
  819. this.videoOption = {
  820. mode: 'live',
  821. uid: this.liveObj.uid, //this.playChannelId egsxlptzdq
  822. cid: this.playChannelId,
  823. openId: this.userInfo.userAccount,
  824. isAutoChange: false,
  825. forceVideo: false,
  826. }
  827. },
  828. async initLive(){
  829. console.log(this.playChannelId,7111)
  830. this.liveObj = await this.getLiveUid(this.playChannelId);
  831. this.initLiveOk = true
  832. let optionsData = {}
  833. optionsData.mode = 'live';
  834. optionsData.forceVideo = false;
  835. optionsData.channelId = this.playChannelId; // 频道ID '2553128'
  836. optionsData.openId = this.userInfo.userAccount; // 用户openId this.userInfo.userAccount 'oQ5eX5BCtSjkE1ct8CzvxGWgh0hQ'
  837. optionsData.userId = this.liveObj.uid // 2.0.0及以上版本的demo需要使用 userId 设置学员唯一id 'egsxlptzdq'
  838. let self = this
  839. this.closePlv()
  840. plv.init(optionsData)
  841. .then(({ detail, chat }) => {
  842. self.liveDetail = detail
  843. // 设置mode为live的videoOption
  844. this.setLiveOption();
  845. if (detail.isPPT) {
  846. chat.on(chat.events.SLICESTART, () => {
  847. // 开始直播
  848. });
  849. } else {
  850. plv.api.getOrdinaryLiveStatus(detail.stream);
  851. }
  852. });
  853. },
  854. openSetting(res){
  855. console.log(res,98)
  856. },
  857. getCameraSetting () {
  858. const self = this
  859. wx.getSetting({
  860. success: res => {
  861. if (res.authSetting['scope.camera']) {
  862. // 用户已经授权
  863. self.showSet = false
  864. } else {
  865. // 用户还没有授权,向用户发起授权请求
  866. wx.authorize({
  867. scope: 'scope.camera',
  868. success() { // 用户同意授权
  869. self.showSet = false
  870. },
  871. fail() { // 用户不同意授权
  872. self.showSet = true
  873. /* wx.showToast({
  874. title: '摄像头授权失败',
  875. icon: 'none',
  876. duration: 3000
  877. }) */
  878. }
  879. })
  880. }
  881. },
  882. fail: res => {
  883. }
  884. })
  885. },
  886. openJY(){
  887. this.$u.toast('此功能正在开发中');
  888. },
  889. //播放笔记视频
  890. async playNoteVideo(item) {
  891. console.log(item,'noteItem')
  892. if (this.timer) {
  893. clearInterval(this.timer);
  894. }
  895. if (this.vid) {
  896. //切换视频
  897. var polyvPlayerContext = this.selectComponent('#playerVideo');
  898. polyvPlayerContext.changeVid(item.recordingUrl);
  899. } else {
  900. this.vid = item.recordingUrl;
  901. }
  902. this.recordObj = {videoCurrentTime:item.noteSecond}
  903. if (this.recordObj.videoCurrentTime) {
  904. this.needSeek = true; //需要跳转到播放记录
  905. }
  906. this.startStatus = true;
  907. //获取节笔记
  908. this.getNoteList();
  909. },
  910. //正常播放视频
  911. async playVideo(item) {
  912. console.log(item)
  913. if (this.timer) {
  914. clearInterval(this.timer);
  915. }
  916. if (this.vid) {
  917. //切换视频
  918. var polyvPlayerContext = this.selectComponent('#playerVideo');
  919. polyvPlayerContext.changeVid(item.recordingUrl);
  920. } else {
  921. this.vid = item.recordingUrl;
  922. }
  923. this.recordObj = null
  924. this.recordObj = await this.getRecordLast();
  925. this.needSeek = true; //跳转到播放记录
  926. this.startStatus = true;
  927. //获取节笔记
  928. this.getNoteList();
  929. },
  930. getRecordLast() {
  931. let self = this;
  932. return new Promise(resolve => {
  933. let data = {
  934. gradeId: Number(self.gradeId),
  935. goodsId: Number(self.goodsId),
  936. sectionId: Number(self.playSectionId),
  937. courseId: Number(self.courseId),
  938. chapterId: parseInt(self.chapterId),
  939. moduleId: parseInt(self.moduleId)
  940. };
  941. self.$api.recordLast(data).then(res => {
  942. resolve(res.data.data);
  943. });
  944. });
  945. },
  946. jumpNote(item) {
  947. this.noteId = item.noteId;
  948. //没视频播放
  949. if(this.playSectionId==0){
  950. console.log('即将跳到笔记位置1')
  951. this.$u.toast('即将跳到笔记位置');
  952. this.$store.commit('setPlaySectionId', {playSectionId :item.sectionId});
  953. this.$store.commit('setPlayVID', {playVID :item.recordingUrl});
  954. this.playNoteVideo(item);
  955. }else{
  956. //正在看当前笔记视频
  957. console.log('即将跳到笔记位置2')
  958. this.$u.toast('即将跳到笔记位置');
  959. //跳到笔记时刻
  960. var polyvPlayerContext = this.selectComponent('#playerVideo');
  961. polyvPlayerContext.seek(item.noteSecond);
  962. polyvPlayerContext.play();
  963. }
  964. },
  965. postNote() {
  966. let self = this;
  967. if (!(this.playSectionId > 0)) {
  968. this.$u.toast('目前无播放视频');
  969. return;
  970. }
  971. if (!this.noteValue) {
  972. this.$u.toast('请输入内容');
  973. return;
  974. }
  975. if(!this.gradeId){
  976. this.$u.toast('暂无班级数据');
  977. return;
  978. }
  979. var polyvPlayerContext = this.selectComponent('#playerVideo');
  980. let noteDate = this.$method.getZeroTime();
  981. let noteSecond = polyvPlayerContext.getCurrentTime();
  982. console.log(noteSecond,698)
  983. if (!noteSecond) {
  984. if(noteSecond==0){
  985. //播放结束
  986. noteSecond = polyvPlayerContext.getDuration();
  987. console.log(noteSecond,63398)
  988. }
  989. if(!noteSecond){
  990. this.$u.toast('视频暂未开始');
  991. return;
  992. }
  993. }
  994. let data = {
  995. gradeId: this.gradeId,
  996. goodsId: this.goodsId,
  997. sectionId: this.playSectionId,
  998. courseId: this.courseId,
  999. noteText: this.noteValue,
  1000. noteDate: noteDate,
  1001. noteSecond: noteSecond
  1002. };
  1003. this.$api.postNote(data).then(res => {
  1004. if (res.data.code == 200) {
  1005. this.$u.toast('发布成功');
  1006. self.getNoteList();
  1007. this.noteValue = '';
  1008. }
  1009. });
  1010. },
  1011. getGradeInfo() {
  1012. let self = this;
  1013. this.$store.state.allowLoading = false;
  1014. this.$api.goodsGradeInfo(this.gradeId).then(res => {
  1015. if (res.data.code == 200) {
  1016. self.gradeDetail = res.data.data;
  1017. if(self.needProfileModal){
  1018. return
  1019. }
  1020. if(self.gradeDetail.learningStatus==2){
  1021. uni.showModal({
  1022. showCancel:false,
  1023. cancelText: '返回',
  1024. content: '当前课程正在申请中,请耐心等待',
  1025. success: function(resultst) {
  1026. uni.navigateBack();
  1027. }
  1028. });
  1029. }
  1030. if(self.gradeDetail.learningStatus==3&&(Number(self.gradeDetail.learningTimeStart)>Number((new Date())/1000))){
  1031. uni.showModal({
  1032. showCancel:false,
  1033. cancelText: '返回',
  1034. content: '当前课程正在申请中,请耐心等待',
  1035. success: function(resultst) {
  1036. uni.navigateBack();
  1037. }
  1038. });
  1039. }
  1040. }
  1041. });
  1042. this.$store.state.allowLoading = true;
  1043. },
  1044. getNoteList() {
  1045. let self = this;
  1046. self.noteList = [];
  1047. let data = { courseId: this.courseId, gradeId: this.gradeId, goodsId: this.goodsId }
  1048. if(this.playSectionId>0){
  1049. data.sectionId = this.playSectionId
  1050. }
  1051. this.$api.noteList(data).then(res => {
  1052. if (res.data.code == 200) {
  1053. self.noteList = res.data.rows;
  1054. }
  1055. });
  1056. },
  1057. delAnswer(answerId) {
  1058. let self = this;
  1059. let data = { answerId: answerId, status: -1 };
  1060. this.$api.delAnswer(data).then(res => {
  1061. if (res.data.code == 200) {
  1062. self.getAnswerList();
  1063. }
  1064. });
  1065. },
  1066. clearCtx() {
  1067. console.log(4234);
  1068. this.placeholder = '您可以在这里输入答疑内容';
  1069. this.ctxValue = '';
  1070. this.assignUserId = 0;
  1071. },
  1072. replyContent(item) {
  1073. this.assignUserId = item.userId;
  1074. this.placeholder = '@' + item.realname;
  1075. },
  1076. delContent(item) {
  1077. this.delAnswer(item.answerId);
  1078. },
  1079. postAnswer() {
  1080. let self = this;
  1081. let data = { courseId: this.courseId, answerText: this.ctxValue, goodsId: this.goodsId };
  1082. if (this.assignUserId > 0) {
  1083. data.assignUserId = this.assignUserId;
  1084. }
  1085. this.$api.postAnswer(data).then(res => {
  1086. if (res.data.code == 200) {
  1087. this.$u.toast('发布成功');
  1088. self.getAnswerList();
  1089. this.placeholder = '您可以在这里输入答疑内容';
  1090. this.ctxValue = '';
  1091. this.assignUserId = 0;
  1092. }
  1093. });
  1094. },
  1095. postContent() {
  1096. if (!this.ctxValue||this.ctxValue=='') {
  1097. this.$u.toast('请输入内容');
  1098. return
  1099. }
  1100. this.postAnswer();
  1101. },
  1102. postStudyRecord(status = 0, sectionId = this.playSectionId) {
  1103. console.log('status',status)
  1104. let currentTime = 0;
  1105. let PlayDuration = 0
  1106. var polyvPlayerContext = this.selectComponent('#playerVideo');
  1107. if (polyvPlayerContext) {
  1108. currentTime = polyvPlayerContext.getCurrentTime(); //总的视频播放时刻
  1109. PlayDuration = polyvPlayerContext.getVideoPlayDuration();//本次看的时长
  1110. }
  1111. if(this.playChannelId>0){
  1112. currentTime = 2;//直播无法获取,无论开始结束都传2秒
  1113. }
  1114. let self = this;
  1115. let data = {
  1116. photo: self.ossAvatarUrl,
  1117. sectionId: parseInt(sectionId),
  1118. goodsId: parseInt(self.goodsId),
  1119. courseId: parseInt(self.courseId),
  1120. studyDuration: parseInt(PlayDuration > 0 ? PlayDuration : self.studyDuration),
  1121. gradeId: parseInt(self.gradeId),
  1122. chapterId: parseInt(self.chapterId),
  1123. moduleId: parseInt(self.moduleId),
  1124. videoCurrentTime: parseInt(currentTime > 0 ? currentTime : self.studyDuration)
  1125. };
  1126. if (status > 0) {
  1127. console.log(sectionId,'sectionId')
  1128. data.status = status;
  1129. }
  1130. console.log('提交接口', data);
  1131. this.$api.studyRecord(data).then(res => {
  1132. if (status > 0) {
  1133. let moduleId = this.moduleId || 0;
  1134. let chapterId = this.chapterId || 0;
  1135. let playNextIdisRebuild = `moduleId${moduleId}chapterId${chapterId}sectionId${sectionId}isRebuild`;
  1136. let playNextId = `moduleId${moduleId}chapterId${chapterId}sectionId${sectionId}`; //拼接对应章节唯一id
  1137. console.log(playNextId,'playNextId')
  1138. console.log(playNextIdisRebuild,'playNextIdisRebuild')
  1139. uni.$emit('playNext'+playNextIdisRebuild,{fromRebuild:this.isRebuild}); //通知播放结束,不来自重修目录的点击不用弹窗学习下一节
  1140. uni.$emit('playNext'+playNextId); //通知播放结束
  1141. }
  1142. self.ossAvatarUrl = ''
  1143. console.log(res,'res');
  1144. });
  1145. },
  1146. uploadFile(options, int) {
  1147. var self = this;
  1148. return new Promise((resolve, reject) => {
  1149. var data = {
  1150. imageStatus: int
  1151. };
  1152. self.$api.aliyunpolicy(data).then(res => {
  1153. if (res.data.code != 200) {
  1154. self.$method.showToast('签名错误' + JSON.stringify(res.data));
  1155. return;
  1156. }
  1157. var ossToken = res.data.data.resultContent;
  1158. if (ossToken.host == null || ossToken.host == undefined) {
  1159. self.$method.showToast('上传路径报错' + JSON.stringify(res.data));
  1160. return;
  1161. }
  1162. uni.uploadFile({
  1163. url: ossToken.host,
  1164. name: 'file',
  1165. filePath: options,
  1166. fileType: 'image',
  1167. header: {
  1168. AuthorizationToken: 'WX ' + uni.getStorageSync('token')
  1169. },
  1170. formData: {
  1171. key: ossToken.dir,
  1172. OSSAccessKeyId: ossToken.accessid,
  1173. policy: ossToken.policy,
  1174. Signature: ossToken.signature,
  1175. callback: ossToken.callback,
  1176. success_action_status: 200
  1177. },
  1178. success: result => {
  1179. if (result.statusCode === 200) {
  1180. self.ossAvatarUrl = ossToken.dir;
  1181. resolve();
  1182. } else {
  1183. uni.showToast({
  1184. title: '上传失败',
  1185. icon: 'none'
  1186. });
  1187. return;
  1188. }
  1189. },
  1190. fail: error => {
  1191. uni.showToast({
  1192. title: '上传接口报错' + error,
  1193. icon: 'none'
  1194. });
  1195. return;
  1196. }
  1197. });
  1198. });
  1199. });
  1200. },
  1201. imageInfos() {
  1202. var self = this;
  1203. return new Promise((resolve, reject) => {
  1204. uni.getImageInfo({
  1205. src: self.avatarUrl,
  1206. success: async res => {
  1207. let canvasWidth = res.width; //图片原始长宽
  1208. let canvasHeight = res.height;
  1209. if (canvasWidth > 2000 || canvasHeight > 2000) {
  1210. uni.compressImage({
  1211. src: self.avatarUrl,
  1212. quality: 75,
  1213. width: '35%',
  1214. height: '35%',
  1215. success: async rest => {
  1216. const waitUpload = await self.uploadFile(rest.tempFilePath, 0);
  1217. resolve();
  1218. }
  1219. });
  1220. } else if (canvasWidth > 1000 || canvasHeight > 1000) {
  1221. uni.compressImage({
  1222. src: self.avatarUrl,
  1223. quality: 75,
  1224. width: '50%',
  1225. height: '50%',
  1226. success: async rest => {
  1227. const waitUpload = await self.uploadFile(rest.tempFilePath, 0);
  1228. resolve();
  1229. }
  1230. });
  1231. } else {
  1232. console.log('无需压缩');
  1233. const waitUpload = await self.uploadFile(self.avatarUrl, 0);
  1234. resolve();
  1235. }
  1236. }
  1237. });
  1238. });
  1239. },
  1240. timeEvent() {
  1241. let self = this;
  1242. var polyvPlayerContext = this.selectComponent('#playerVideo');
  1243. if (polyvPlayerContext != null) {
  1244. this.playTime = polyvPlayerContext.getCurrentTime() //播放时刻
  1245. // console.log(this.playTime,789,this.photoHistoryList)
  1246. //判断是否需要拍照
  1247. if (this.photoNum > 0) {
  1248. this.configPhoto()
  1249. let photoTime =0; //获取拍照秒数
  1250. for(let i=0;i<this.photoList.length;i++){
  1251. photoTime = Number(this.photoList[i]); //获取拍照秒数
  1252. if (photoTime < this.playTime&&photoTime>this.playTime-8) { //3秒区间内才触发拍照,避免拉动滚动条
  1253. if(this.photoHistoryList.indexOf(i)<0){ //不存在拍照历史则拍照
  1254. //启动拍照
  1255. //暂停
  1256. polyvPlayerContext.exitFullScreen();
  1257. polyvPlayerContext.pause();
  1258. this.photoHistoryList.push(i)
  1259. this.photoIndex = i
  1260. this.openPhoto();
  1261. }
  1262. }
  1263. }
  1264. }
  1265. }
  1266. },
  1267. onStateChange(newstate, oldstate) {
  1268. if (newstate.detail.newstate == 'playing') {
  1269. if (this.needSeek) {
  1270. var polyvPlayerContext = this.selectComponent('#playerVideo');
  1271. if(this.recordObj.videoCurrentTime){
  1272. console.log('seek')
  1273. polyvPlayerContext.seek(this.recordObj.videoCurrentTime);
  1274. }else{
  1275. polyvPlayerContext.seek(1);//避免相同节继续播放
  1276. }
  1277. polyvPlayerContext.play();
  1278. this.needSeek = false;
  1279. }
  1280. //开始播放
  1281. if (this.timer) {
  1282. clearInterval(this.timer);
  1283. }
  1284. this.timer = setInterval(this.timeEvent, 1000); //定时器
  1285. }
  1286. if (newstate.detail.newstate == 'pause') {
  1287. //暂停提交记录
  1288. /* this.ossAvatarUrl = ""
  1289. this.postStudyRecord() */
  1290. }
  1291. if (newstate.detail.newstate == 'ended') {
  1292. this.postStudyRecord(1);
  1293. // uni.$emit('playNext') //播放重修下一节
  1294. }
  1295. },
  1296. //拍照
  1297. openPhoto() {
  1298. this.photoPopup = true;
  1299. uni.authorize({
  1300. scope: 'scope.camera',
  1301. success() {
  1302. }
  1303. })
  1304. },
  1305. async submit() {
  1306. const waitYS = await this.imageInfos();
  1307. this.postCoursePhotoRecord()
  1308. this.postStudyRecord(); //提交记录
  1309. //恢复播放
  1310. var polyvPlayerContext = this.selectComponent('#playerVideo');
  1311. if (polyvPlayerContext != null) {
  1312. polyvPlayerContext.play();
  1313. }
  1314. },
  1315. //确认拍照
  1316. takePhoto() {
  1317. var self = this;
  1318. const ctx = uni.createCameraContext();
  1319. ctx.takePhoto({
  1320. quality: 'high',
  1321. success: res => {
  1322. console.log(res.tempImagePath);
  1323. self.avatarUrl = res.tempImagePath;
  1324. self.submit();
  1325. self.photoPopup = false;
  1326. },
  1327. fail: err => {
  1328. console.log(err);
  1329. }
  1330. });
  1331. },
  1332. //拍照报错
  1333. error(e) {
  1334. console.log(e.detail);
  1335. },
  1336. //关闭相机
  1337. closePhoto() {
  1338. this.photoPopup = false;
  1339. },
  1340. getGoodsDetail() {
  1341. let self = this;
  1342. this.$api.goodsDetail(this.goodsId).then(res => {
  1343. self.goodsData = res.data.data;
  1344. self.gradeId = self.goodsData.gradeId;
  1345. console.log(self.gradeId, "班级ID");
  1346. this.courseBusiness()
  1347. this.courseHandouts();
  1348. self.getMenuList();
  1349. self.getReMenuList(); //获取重修目录
  1350. setTimeout(function(){
  1351. if(!self.needProfileModal){
  1352. self.getGradeInfo()
  1353. }
  1354. },500)
  1355. //获取节笔记
  1356. this.getNoteList();
  1357. if (self.goodsData.goodsPlayConfig) {
  1358. self.goodsPlayConfig = JSON.parse(self.goodsData.goodsPlayConfig);
  1359. if (self.goodsPlayConfig.autoPlay > 0) {
  1360. self.autoplay = true;
  1361. }
  1362. if (self.goodsPlayConfig.drag > 0) {
  1363. self.isAllowSeek = 'yes';
  1364. }
  1365. if (self.goodsPlayConfig.speed > 0) {
  1366. self.playbackRate = [0.5, 0.8, 1.0, 1.25, 1.5, 2.0];
  1367. }
  1368. }
  1369. if (self.goodsData.goodsPhotographConfig) {
  1370. self.goodsPhotographConfig = JSON.parse(self.goodsData.goodsPhotographConfig);
  1371. if (self.goodsPhotographConfig.photoNum>0) {
  1372. self.photoNum = self.goodsPhotographConfig.photoNum
  1373. console.log(self.photoNum,777777)
  1374. }
  1375. }
  1376. });
  1377. },
  1378. startVideo() {
  1379. this.startStatus = true;
  1380. },
  1381. getAnswerList() {
  1382. let self = this;
  1383. this.$api.answerList({ courseId: this.courseId,goodsId: this.goodsId }).then(res => {
  1384. if (res.data.code == 200) {
  1385. self.answerList = res.data.rows;
  1386. }
  1387. });
  1388. },
  1389. getReMenuList() {
  1390. let self = this;
  1391. this.$api.reMenuList({ courseId: this.courseId, rebuild: 1, gradeId: this.gradeId }).then(res => {
  1392. if (res.data.code == 200) {
  1393. for (let i = 0; i < res.data.rows.length; i++) {
  1394. let item = res.data.rows[i];
  1395. item.down = true;
  1396. item.id = item.menuId;
  1397. item.name = item.menuName;
  1398. }
  1399. self.reMenuList = res.data.rows;
  1400. if(self.reMenuList.length>0){
  1401. self.list = [
  1402. {
  1403. name: '目录'
  1404. },
  1405. {
  1406. name: '讲义'
  1407. },
  1408. {
  1409. name: '笔记'
  1410. },
  1411. {
  1412. name: '答疑'
  1413. },
  1414. {name:'重修目录'}
  1415. ];
  1416. this.current = 0;
  1417. } else {
  1418. self.list = [
  1419. {
  1420. name: '目录'
  1421. },
  1422. {
  1423. name: '讲义'
  1424. },
  1425. {
  1426. name: '笔记'
  1427. },
  1428. {
  1429. name: '答疑'
  1430. }
  1431. ];
  1432. this.current = 0;
  1433. }
  1434. }
  1435. });
  1436. },
  1437. getMenuList() {
  1438. let self = this;
  1439. this.$api.reMenuList({ courseId: this.courseId, gradeId: this.gradeId }).then(res => {
  1440. if (res.data.code == 200) {
  1441. for (let i = 0; i < res.data.rows.length; i++) {
  1442. let item = res.data.rows[i];
  1443. item.down = true;
  1444. item.id = item.menuId;
  1445. item.name = item.menuName;
  1446. }
  1447. self.menuList = res.data.rows;
  1448. }
  1449. });
  1450. },
  1451. courseDetail() {
  1452. let self = this;
  1453. this.$api.courseDetail(this.courseId).then(res => {
  1454. if (res.data.code == 200) {
  1455. self.detail = res.data.data;
  1456. uni.setNavigationBarTitle({
  1457. title:self.detail.courseName
  1458. })
  1459. }
  1460. });
  1461. },
  1462. open(item) {
  1463. item.showChildren = !item.showChildren;
  1464. },
  1465. change(index) {
  1466. this.current = index;
  1467. },
  1468. openDocument() {
  1469. let self = this;
  1470. let url = this.$method.splitImgHost(this.courseHandoutsData.handoutsUrl)
  1471. console.log(url)
  1472. uni.downloadFile({
  1473. url: url,
  1474. success: function (res) {
  1475. console.log(999)
  1476. var filePath = res.tempFilePath;
  1477. uni.openDocument({
  1478. filePath: filePath,
  1479. showMenu: self.courseHandoutsData.canDownload == 1 ? true : false,
  1480. success: function (res) {
  1481. console.log(res,'打开文档成功');
  1482. },
  1483. fail:function(err) {
  1484. console.log(err)
  1485. uni.showToast({
  1486. icon:'none',
  1487. title:'文档地址错误'
  1488. })
  1489. }
  1490. });
  1491. },
  1492. fail:(err) => {
  1493. uni.showModal({
  1494. title:'提示',
  1495. content:'文档错误,'+err.errMsg,
  1496. showCancel:false
  1497. })
  1498. }
  1499. });
  1500. }
  1501. }
  1502. };
  1503. </script>
  1504. <style lang="scss" scope>
  1505. .btnSet{
  1506. width: 440rpx;
  1507. height: 80rpx;
  1508. background: #007AFF;
  1509. border-radius: 40rpx;
  1510. color: #FFFFFF;
  1511. font-size: 28rpx;
  1512. line-height: 80rpx;
  1513. }
  1514. .btnReply {
  1515. width: 80rpx;
  1516. height: 40rpx;
  1517. background: #e3f0ff;
  1518. border-radius: 16rpx;
  1519. text-align: center;
  1520. color: #007aff;
  1521. }
  1522. .btnDel {
  1523. width: 80rpx;
  1524. height: 40rpx;
  1525. background: #ffedf0;
  1526. border-radius: 16rpx;
  1527. text-align: center;
  1528. color: #ff2d55;
  1529. }
  1530. .btnReply {
  1531. width: 80rpx;
  1532. height: 40rpx;
  1533. background: #e3f0ff;
  1534. border-radius: 16rpx;
  1535. font-size: 24rpx;
  1536. }
  1537. .lecture-box {
  1538. display: flex;
  1539. align-items: center;
  1540. height: 80rpx;
  1541. background: #FFFFFF;
  1542. border-radius: 16rpx 16rpx 16rpx 16rpx;
  1543. .title {
  1544. padding:10rpx;
  1545. flex:1;
  1546. overflow: hidden;
  1547. text-overflow: ellipsis;
  1548. white-space: nowrap;
  1549. color:#333;
  1550. font-weight: bold;
  1551. font-size: 32rpx;
  1552. }
  1553. .btn {
  1554. display: flex;
  1555. align-items: center;
  1556. justify-content: center;
  1557. width:80rpx;
  1558. height:80rpx;
  1559. background: #FFFFFF;
  1560. box-shadow: -4rpx 0rpx 4rpx 0rpx rgba(0,0,0,0.1);
  1561. border-radius: 16rpx 16rpx 16rpx 16rpx;
  1562. }
  1563. }
  1564. .lecture-content {
  1565. background:#fff;
  1566. margin-top:10rpx;
  1567. padding:10rpx;
  1568. border-radius:16rpx;
  1569. }
  1570. .photoBox {
  1571. background-color: #FFFFFF;
  1572. border-radius: 32px 32px 0px 0px;
  1573. .photoTop {
  1574. height: 74upx;
  1575. display: flex;
  1576. align-items: center;
  1577. justify-content: space-between;
  1578. padding: 0upx 38upx;
  1579. .sqzz {
  1580. width: 28upx;
  1581. height: 28upx;
  1582. display: flex;
  1583. align-items: center;
  1584. justify-content: center;
  1585. }
  1586. .centersq {
  1587. color: #333;
  1588. font-size: 30upx;
  1589. font-weight: 500;
  1590. }
  1591. }
  1592. .photoCenter {
  1593. width: 750upx;
  1594. height: 979upx;
  1595. position: relative;
  1596. .custom {
  1597. width: 750upx;
  1598. height: 979upx;
  1599. position: absolute;
  1600. z-index: 1000;
  1601. top: 0;
  1602. left: 0;
  1603. image {
  1604. width: 100%;
  1605. height: 100%;
  1606. }
  1607. }
  1608. }
  1609. .btnResult {
  1610. height: 100rpx;
  1611. width: 100%;
  1612. background-color: #07c160;
  1613. text-align: center;
  1614. line-height: 100upx;
  1615. color: #fff;
  1616. font-size: 32upx;
  1617. font-weight: bold;
  1618. }
  1619. }
  1620. .chat_box {
  1621. display: flex;
  1622. padding: 20rpx;
  1623. justify-content: space-between;
  1624. }
  1625. .chat3 {
  1626. font-size: 30rpx;
  1627. font-family: PingFang SC;
  1628. font-weight: 500;
  1629. color: #666666;
  1630. margin-top: 10rpx;
  1631. }
  1632. .chat2 {
  1633. font-size: 20rpx;
  1634. font-family: PingFang SC;
  1635. font-weight: 500;
  1636. color: #999999;
  1637. margin-top: 10rpx;
  1638. }
  1639. .chat1 {
  1640. font-size: 24rpx;
  1641. font-family: PingFang SC;
  1642. font-weight: 500;
  1643. color: #333333;
  1644. }
  1645. .leftPadding {
  1646. margin-left: 8rpx;
  1647. }
  1648. .t2Content {
  1649. font-size: 28rpx;
  1650. font-family: PingFang SC;
  1651. font-weight: bold;
  1652. color: #999999;
  1653. line-height: 48rpx;
  1654. }
  1655. .tBox2 {
  1656. display: flex;
  1657. padding-top: 10rpx;
  1658. color: #333333;
  1659. font-size: 30rpx;
  1660. }
  1661. .tBox {
  1662. display: flex;
  1663. align-items: center;
  1664. padding-top: 10rpx;
  1665. }
  1666. .title {
  1667. font-size: 24rpx;
  1668. color: #999999;
  1669. }
  1670. page {
  1671. padding-top: 10px;
  1672. padding-top: constant(safe-area-inset-top);
  1673. padding-top: env(safe-area-inset-top);
  1674. }
  1675. .inputBottom {
  1676. position: fixed;
  1677. left: 0;
  1678. bottom: 0;
  1679. background: #ffffff;
  1680. height: 98rpx;
  1681. display: flex;
  1682. align-items: center;
  1683. width: 100%;
  1684. .flex_auto {
  1685. flex:1;
  1686. margin-left: 10% ;
  1687. .input {
  1688. height:60rpx;
  1689. }
  1690. }
  1691. .btn {
  1692. color: #007AFF;font-size: 30rpx;font-weight: bold;width: 15%;text-align: center;
  1693. }
  1694. }
  1695. .noteBox {
  1696. width: 100%;
  1697. background: #ffffff;
  1698. padding: 10rpx;
  1699. border-radius: 16rpx;
  1700. }
  1701. .dateBox {
  1702. width: 216rpx;
  1703. height: 48rpx;
  1704. background: #ffffff;
  1705. border-radius: 24rpx;
  1706. font-size: 24rpx;
  1707. color: #666666;
  1708. text-align: center;
  1709. line-height: 48rpx;
  1710. margin: 20rpx 0;
  1711. }
  1712. .t_content1 {
  1713. color: #007aff;
  1714. margin-left: 10rpx;
  1715. }
  1716. .tag1 {
  1717. border: 2rpx solid #007aff;
  1718. border-radius: 8rpx;
  1719. font-size: 20rpx;
  1720. color: #007aff;
  1721. padding: 5rpx;
  1722. }
  1723. .b_title {
  1724. color: #333333;
  1725. font-size: 30rpx;
  1726. font-weight: bold;
  1727. }
  1728. page {
  1729. background: #eaeef1;
  1730. }
  1731. .menuBox {
  1732. width: 100%;
  1733. background: #ffffff;
  1734. border-radius: 16rpx;
  1735. padding: 20rpx;
  1736. margin-bottom: 20rpx;
  1737. }
  1738. .btnspric {
  1739. border-top: 1rpx solid #eee;
  1740. display: flex;
  1741. align-items: center;
  1742. justify-content: space-between;
  1743. height: 108rpx;
  1744. padding-left: 43rpx;
  1745. padding-right: 32rpx;
  1746. }
  1747. .btnspric > .lefprL {
  1748. font-size: 36rpx;
  1749. color: #0c141f;
  1750. font-weight: bold;
  1751. }
  1752. .btnspric > .lefprR {
  1753. padding: 0rpx 24rpx;
  1754. height: 60rpx;
  1755. line-height: 60rpx;
  1756. text-align: center;
  1757. color: #fff;
  1758. background: #32467b;
  1759. border-radius: 24rpx;
  1760. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  1761. }
  1762. .yhj,
  1763. .hdyhj {
  1764. padding: 24rpx 29rpx 24rpx 34rpx;
  1765. }
  1766. .yhj {
  1767. border-bottom: 16rpx solid #f9f9f9;
  1768. }
  1769. .yhjtit {
  1770. font-size: 30rpx;
  1771. color: #0c141f;
  1772. font-weight: 500;
  1773. margin-bottom: 14rpx;
  1774. }
  1775. .yhjList {
  1776. display: flex;
  1777. align-items: center;
  1778. justify-content: space-between;
  1779. margin-bottom: 14rpx;
  1780. }
  1781. .yhjList > .yhjLefts {
  1782. display: flex;
  1783. align-items: center;
  1784. }
  1785. .yhjLefts > .yhl {
  1786. color: #32467b;
  1787. font-size: 30rpx;
  1788. margin-right: 31rpx;
  1789. }
  1790. .yhjLefts > .yhbq {
  1791. font-size: 24rpx;
  1792. color: #ff9500;
  1793. border-radius: 18rpx;
  1794. background-color: rgba(255, 149, 0, 0.2);
  1795. border: 2rpx solid #ff9500;
  1796. height: 38rpx;
  1797. line-height: 38rpx;
  1798. padding: 0rpx 16rpx;
  1799. }
  1800. .ts {
  1801. font-size: 24rpx;
  1802. color: #999;
  1803. margin: 14rpx 0rpx;
  1804. padding-right: 29rpx;
  1805. padding-left: 34rpx;
  1806. }
  1807. .yh {
  1808. padding-top: 20rpx;
  1809. }
  1810. .yh > .yhtitle {
  1811. display: flex;
  1812. align-items: center;
  1813. justify-content: space-between;
  1814. padding-right: 29rpx;
  1815. padding-left: 34rpx;
  1816. }
  1817. .priceBxs {
  1818. display: flex;
  1819. align-items: center;
  1820. }
  1821. .priceBxs > .pricleft {
  1822. border-radius: 24rpx;
  1823. border: 1rpx solid #e91313;
  1824. background-color: rgba(233, 19, 19, 0.1);
  1825. padding: 0rpx 18rpx;
  1826. height: 49rpx;
  1827. line-height: 49rpx;
  1828. text-align: center;
  1829. font-size: 30rpx;
  1830. font-weight: 500;
  1831. color: #e91313;
  1832. margin-right: 13rpx;
  1833. }
  1834. .topBox {
  1835. padding: 32rpx 32rpx 24rpx;
  1836. border-bottom: 1rpx solid #eeeeee;
  1837. }
  1838. .topBox > .boldFonstType {
  1839. font-weight: 500;
  1840. font-size: 30rpx;
  1841. margin: 16rpx 0rpx 23rpx;
  1842. }
  1843. .topBox > .firstTopL {
  1844. display: flex;
  1845. align-items: center;
  1846. }
  1847. .topBox > .firstTopL > .imageBs {
  1848. width: 331rpx;
  1849. height: 160rpx;
  1850. border-radius: 6rpx;
  1851. overflow: hidden;
  1852. margin-right: 8rpx;
  1853. box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(47, 67, 121, 0.08);
  1854. }
  1855. .topBox > .firstTopL > .imageBs > image {
  1856. width: 100%;
  1857. height: 100%;
  1858. }
  1859. .topBox > .firstTopL > .textBs {
  1860. font-size: 30rpx;
  1861. font-weight: bold;
  1862. color: #0c141f;
  1863. }
  1864. .content {
  1865. padding: 24rpx;
  1866. text-align: left;
  1867. }
  1868. .catalogBox {
  1869. display: flex;
  1870. align-items: center;
  1871. flex-wrap: nowrap;
  1872. overflow-x: auto;
  1873. padding-left: 38rpx;
  1874. max-height: 305rpx;
  1875. overflow-y: auto;
  1876. transition: all 0.4s;
  1877. }
  1878. .catalogBox > .catalogA {
  1879. min-width: 200rpx;
  1880. height: 48rpx;
  1881. line-height: 48rpx;
  1882. // text-align: center;
  1883. border: 2rpx solid transparent;
  1884. white-space: nowrap;
  1885. text-overflow: ellipsis;
  1886. overflow: hidden;
  1887. word-break: break-all;
  1888. border-radius: 10rpx;
  1889. background: rgba(22, 119, 255, 0.05);
  1890. padding-left: 19rpx;
  1891. box-sizing: border-box;
  1892. padding-right: 15rpx;
  1893. margin-right: 16rpx;
  1894. margin-bottom: 20rpx;
  1895. margin-top: 15rpx;
  1896. font-size: 24rpx;
  1897. color: #666;
  1898. }
  1899. .catalogBox > .activesq {
  1900. border-color: #1677ff;
  1901. }
  1902. .changeCatalogBox {
  1903. display: block;
  1904. }
  1905. .catalogBox::-webkit-scrollbar {
  1906. display: none; /* Chrome Safari */
  1907. }
  1908. .box {
  1909. position: relative;
  1910. top: 650rpx;
  1911. padding-bottom: 88rpx;
  1912. margin: 20rpx;
  1913. }
  1914. .price_t2 {
  1915. font-size: 18rpx;
  1916. font-family: PingFang SC;
  1917. font-weight: 500;
  1918. text-decoration: line-through;
  1919. color: #999999;
  1920. }
  1921. .price_t1 {
  1922. font-size: 33rpx;
  1923. font-family: PingFang SC;
  1924. font-weight: bold;
  1925. color: #e91313;
  1926. }
  1927. .sc_t {
  1928. font-size: 22rpx;
  1929. color: #000000;
  1930. }
  1931. .sc {
  1932. width: 29rpx;
  1933. height: 29rpx;
  1934. }
  1935. .buy {
  1936. width: 138rpx;
  1937. height: 48rpx;
  1938. line-height: 48rpx;
  1939. background: #32467b;
  1940. border-radius: 10rpx;
  1941. color: #ffffff;
  1942. font-size: 28rpx;
  1943. text-align: center;
  1944. vertical-align: middle;
  1945. position: absolute;
  1946. right: 30rpx;
  1947. }
  1948. .video_body {
  1949. padding-bottom: 96rpx;
  1950. }
  1951. .footer_tab {
  1952. position: fixed;
  1953. bottom: 0;
  1954. height: 96rpx;
  1955. width: 100%;
  1956. background-color: #ffffff;
  1957. }
  1958. .tj_box {
  1959. width: 50%;
  1960. display: inline-block;
  1961. text-align: center;
  1962. margin: 10rpx 0;
  1963. }
  1964. .teacher_t {
  1965. font-size: 24rpx;
  1966. font-family: PingFang SC;
  1967. font-weight: 400;
  1968. color: #666666;
  1969. line-height: 36rpx;
  1970. margin-left: 15rpx;
  1971. }
  1972. .teacher_img {
  1973. width: 87rpx;
  1974. height: 129rpx;
  1975. }
  1976. .t2 {
  1977. font-size: 24rpx;
  1978. font-family: PingFang SC;
  1979. color: #666666;
  1980. line-height: 36rpx;
  1981. margin: 15rpx;
  1982. }
  1983. .r_t2 {
  1984. width: 201rpx;
  1985. height: 49rpx;
  1986. background: rgba(22, 119, 255, 0.05);
  1987. border: 1rpx solid #32467b;
  1988. border-radius: 16rpx;
  1989. color: #666666;
  1990. font-size: 23rpx;
  1991. text-align: center;
  1992. display: flex;
  1993. align-items: center;
  1994. padding: 5rpx;
  1995. }
  1996. .scroll_box {
  1997. width: 100%;
  1998. height: 60rpx;
  1999. background: #ffffff;
  2000. box-shadow: 0rpx 0rpx 16rpx 4rpx rgba(145, 156, 178, 0.1);
  2001. white-space: nowrap;
  2002. overflow: hidden;
  2003. margin: 15rpx 0;
  2004. }
  2005. .r_sliper {
  2006. padding: 0 20rpx;
  2007. }
  2008. .top_line {
  2009. width: 6rpx;
  2010. height: 22rpx;
  2011. background: #32467b;
  2012. margin-right: 10rpx;
  2013. }
  2014. .video_t2 {
  2015. font-size: 24rpx;
  2016. font-family: PingFang SC;
  2017. font-weight: 500;
  2018. color: #666666;
  2019. }
  2020. .video_t1 {
  2021. height: 80rpx;
  2022. color: #333333;
  2023. line-height: 80rpx;
  2024. font-size: 30rpx;
  2025. font-family: PingFang SC;
  2026. font-weight: bold;
  2027. color: #333333;
  2028. overflow: hidden;
  2029. text-overflow: ellipsis;
  2030. white-space: nowrap;
  2031. }
  2032. .video_t1_t {
  2033. display: flex;
  2034. flex-direction: column;
  2035. height: 80rpx;
  2036. color: #333333;
  2037. text-align: center;
  2038. align-items: center;
  2039. border-left: solid 1px #d6d6db;
  2040. }
  2041. .video_play {
  2042. position: absolute;
  2043. width: 95rpx;
  2044. height: 95rpx;
  2045. top: 0;
  2046. left: 0;
  2047. right: 0;
  2048. bottom: 0;
  2049. margin: auto;
  2050. }
  2051. .video_box {
  2052. position: relative;
  2053. }
  2054. .rotoct {
  2055. transform: rotate(90deg);
  2056. }
  2057. </style>