detail.vue 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  1. <template>
  2. <view style="padding-bottom: 140rpx">
  3. <nav-bar title="课程详情"></nav-bar>
  4. <view class="videoBox">
  5. <!-- <view > -->
  6. <view class="video_box" v-if="!startStatus">
  7. <image
  8. :src="$method.splitImgHost(detail.coverUrl)"
  9. style="width: 100%; height: 450rpx"
  10. ></image>
  11. <image
  12. v-if="false"
  13. class="video_play"
  14. src="/static/play.png"
  15. @click="startVideo"
  16. ></image>
  17. </view>
  18. <view v-else class="video_box" style="width: 100%; height: 450rpx">
  19. <!-- #ifdef MP-WEIXIN -->
  20. <polyv-player
  21. id="playerVideo"
  22. playerId="playerVideo"
  23. height="450rpx"
  24. :vid="vid"
  25. :showSettingBtn="true"
  26. :enablePlayGesture="true"
  27. :playbackRate="playbackRate"
  28. :isAllowSeek="isAllowSeek"
  29. :autoplay="autoplay"
  30. :startTime="startTime"
  31. @statechange="onStateChange"
  32. ></polyv-player>
  33. <!-- #endif -->
  34. <!-- #ifdef H5 -->
  35. <view v-show="vid" id="player"></view>
  36. <!-- #endif -->
  37. </view>
  38. <view class="cou_title">
  39. <view class="title_name">
  40. <!-- <view class="yearTag" v-if="detail.year">{{detail.year}}</view> -->
  41. <view class="titleTag">{{ detail.goodsName }}</view>
  42. </view>
  43. <view
  44. style="
  45. display: flex;
  46. justify-content: space-between;
  47. margin-top: 13rpx;
  48. "
  49. >
  50. <view class="prices">
  51. <!-- <text v-if="detail.standPrice" class="price_word">¥ {{ detail.standPrice }}</text>
  52. <text v-else class="price_word free">免费</text> -->
  53. <view
  54. class="price_word"
  55. v-if="
  56. !detail.specTemplateId || (!detail.maxPrice && !detail.minPrice)
  57. "
  58. >
  59. {{ detail.standPrice === 0 ? "免费" : `¥${detail.standPrice}` }}
  60. </view>
  61. <!-- 范围价格 -->
  62. <view v-else class="price_word">
  63. <view>{{ detail.minPrice }}</view>
  64. <template v-if="detail.minPrice != detail.maxPrice">
  65. <text>-</text>
  66. <view>{{ detail.maxPrice }}</view>
  67. </template>
  68. </view>
  69. <text v-if="detail.linePrice" class="sale"> ¥ </text>
  70. <text v-if="detail.linePrice" class="price_line">
  71. {{ detail.linePrice }}</text
  72. >
  73. </view>
  74. <view class="noteTag" v-if="!isJx">
  75. <text class="blackFont"
  76. >{{ courseList.length }} 课程 {{ detail.classHours || "-" }}</text
  77. >
  78. 学时
  79. </view>
  80. </view>
  81. </view>
  82. <!-- </view> -->
  83. </view>
  84. <view class="contents" v-if="list.length">
  85. <!-- <u-line color="#D6D6DB" /> -->
  86. <!-- <view style="height: 80rpx;">
  87. <view><u-tabs :list="list" :item-width="itemWidth()" font-size="30" bar-width="24" :current="current" @change="change" active-color="#007AFF"></u-tabs></view>
  88. </view> -->
  89. <view class="tabs">
  90. <view
  91. v-for="(item, index) in list"
  92. :key="index"
  93. class="tab_item"
  94. :class="[{ nactive: current == item.value }]"
  95. @click="change(item.value)"
  96. >{{ item.name }}</view
  97. >
  98. </view>
  99. <view
  100. style="padding: 20rpx; padding-bottom: 100rpx; position: relative"
  101. v-show="current == 0"
  102. >
  103. <view class="content">
  104. <view
  105. v-html="detail.mobileDetailHtml"
  106. style="width: 100%; overflow: hidden"
  107. ></view>
  108. </view>
  109. </view>
  110. <view
  111. style="padding: 20rpx; padding-bottom: 100rpx; position: relative"
  112. v-show="current == 1"
  113. >
  114. <!-- <view v-for="(item, index) in courseItem.courseList" :key="index" > -->
  115. <!-- 视频课 -->
  116. <template v-if="goodsType == 1">
  117. <view v-for="(courseItem, gTindex) in goodsTeacher" :key="gTindex">
  118. <view v-for="(item, index) in courseItem.courseList" :key="index">
  119. <view class="courseItemBox" v-if="item.show && item.show == 1">
  120. <view class="courseItem" @click="openCourse(item)">
  121. <view class="courseName">{{ item.courseName }}</view>
  122. <view>
  123. <image
  124. src="/static/icon/up.png"
  125. class="icon_up"
  126. v-if="item.down"
  127. ></image>
  128. <image
  129. src="/static/icon/down.png"
  130. class="icon_up"
  131. v-if="!item.down"
  132. ></image>
  133. </view>
  134. </view>
  135. <view
  136. v-if="courseItem.teaList && courseItem.teaList.length > 0"
  137. class="teacher_names"
  138. >
  139. <view
  140. v-for="(tea, tindex) in courseItem.teaList"
  141. :key="tindex"
  142. class="names"
  143. :class="[States[gTindex] == tindex ? 'nactive' : '']"
  144. @click.stop="switchTeacher(tea, tindex, gTindex)"
  145. >
  146. <view>{{ tea.aliasName }}</view>
  147. </view>
  148. </view>
  149. <view v-show="!item.down">
  150. <course-tree :isBuy="false"></course-tree>
  151. <u-line></u-line>
  152. </view>
  153. </view>
  154. </view>
  155. </view>
  156. </template>
  157. <!-- 直播课 -->
  158. <template v-else>
  159. <view v-for="(item, index) in courseList" :key="index">
  160. <view class="courseItemBox">
  161. <view class="courseItem" @click="openCourse(item)">
  162. <view class="courseName">{{ item.courseName }}</view>
  163. <view>
  164. <image
  165. src="/static/icon/up.png"
  166. class="icon_up"
  167. v-if="item.down"
  168. ></image>
  169. <image
  170. src="/static/icon/down.png"
  171. class="icon_up"
  172. v-if="!item.down"
  173. ></image>
  174. </view>
  175. </view>
  176. <view v-show="!item.down">
  177. <view v-for="(itemM, indexM) in item.menuList" :key="indexM">
  178. <course-tree :isBuy="false"></course-tree>
  179. <u-line></u-line>
  180. </view>
  181. </view>
  182. </view>
  183. </view>
  184. </template>
  185. </view>
  186. <view
  187. style="padding: 20rpx; padding-bottom: 100rpx; position: relative"
  188. v-show="current == 2"
  189. >
  190. <view v-for="(item, index) in freeMenuList" :key="index">
  191. <view class="courseItemBox">
  192. <view class="courseItem">
  193. <view class="courseName">{{ item.freeExamName }}</view>
  194. </view>
  195. </view>
  196. </view>
  197. </view>
  198. <!-- 讲义资料 -->
  199. <view v-show="current == 3" style="padding: 0 10rpx">
  200. <handouts-box
  201. :isShowSearch="false"
  202. :isShowDownIcon="false"
  203. :handoutsId="detail.handoutsId"
  204. v-if="detail.handoutsId"
  205. />
  206. </view>
  207. </view>
  208. <view class="bottomBox" v-if="!hideBuyState">
  209. <template v-if="!options.isAct">
  210. <view class="icons">
  211. <view class="icon_item ones">
  212. <image src="/static/index/share.png" class="share"></image>
  213. <button type="default" open-type="share" class="bt_share"></button>
  214. <view class="share_w">分享</view>
  215. </view>
  216. <view class="icon_item" v-if="!disCode">
  217. <image
  218. src="/static/index/shopcar.png"
  219. class="shopcar"
  220. @click="toShopcar()"
  221. ></image>
  222. <view class="share_w">购物车</view>
  223. </view>
  224. </view>
  225. <view style="display: flex; color: #ffffff; align-items: center">
  226. <view class="btn1" v-if="!disCode" @click="addCart()">加购物车</view>
  227. <view class="btn2" @click="buy()">立即购买 </view>
  228. </view>
  229. </template>
  230. <template v-else>
  231. <view
  232. class="btn2"
  233. style="color: #ffffff; position: absolute; right: 24rpx"
  234. @click="drawBuy()"
  235. >立即领取
  236. </view>
  237. </template>
  238. </view>
  239. <!-- 已购买过课程的弹窗 -->
  240. <u-popup v-model="bugCourseModel" mode="center" border-radius="40">
  241. <view class="had_bugCourse">
  242. <image src="/pages3/static/imgs/hadBug.png" class="share"></image>
  243. <view class="tips">
  244. <view class="warns">温馨提示</view>
  245. <view class="words">您<text>已购买过</text>该商品课程</view>
  246. <view class="words">可立即前往学习</view>
  247. </view>
  248. <view class="tip_botton">
  249. <view class="cancel_btn" @click="changeKown()">知道了</view>
  250. <view class="confirm_btn" @click="toStudy()">去学习</view>
  251. </view>
  252. </view>
  253. </u-popup>
  254. <!-- 选择规格弹窗 -->
  255. <u-popup v-model="toggleSkuShow" mode="bottom" border-radius="40">
  256. <view class="popup_box">
  257. <view class="check_head">
  258. <view class="headers">
  259. <view class="grade">选择规格</view>
  260. <u-icon
  261. name="close"
  262. color="#9C9C9C"
  263. size="40"
  264. @click="closePop()"
  265. ></u-icon>
  266. </view>
  267. </view>
  268. <view class="check_con">
  269. <scroll-view scroll-y="true" style="height: 600rpx">
  270. <view
  271. v-for="(item, index) in specList"
  272. :key="index"
  273. class="check_items"
  274. >
  275. <view class="grades">{{ item.name }}</view>
  276. <view
  277. class="grade_names"
  278. v-if="index == 0 && specList.length > 1"
  279. >
  280. <view
  281. class="course_items"
  282. v-for="(child, c_index) in item.specAttrList"
  283. :key="c_index"
  284. :class="{ nactive: selectGoodIndex == c_index }"
  285. @click="selectGoodType(c_index)"
  286. >
  287. {{ child.name }}
  288. </view>
  289. </view>
  290. <view v-if="index == 1 || specList.length == 1" class="check_box">
  291. <u-checkbox-group>
  292. <view
  293. v-for="spec in item.specAttrList"
  294. :key="spec.specAttributeId"
  295. >
  296. <view
  297. class="check_box_item"
  298. v-if="spec.goodsId"
  299. :class="spec.check ? 'selected' : ''"
  300. >
  301. <u-checkbox
  302. @change="checkboxChange"
  303. v-model="spec.check"
  304. :name="spec.specAttributeId"
  305. >
  306. <view class="price_box">
  307. <view class="check_box_item_titme">{{
  308. spec.name
  309. }}</view>
  310. <view class="price">¥{{ spec.standPrice }}</view>
  311. </view>
  312. </u-checkbox>
  313. </view>
  314. </view>
  315. </u-checkbox-group>
  316. </view>
  317. </view>
  318. </scroll-view>
  319. </view>
  320. <view class="confirm_btns">
  321. <view class="allprice">
  322. <view>
  323. 总价:<text>¥</text><text>{{ allPrice }}</text>
  324. </view>
  325. <text>已选择{{ goodsIds.length }}个商品</text>
  326. </view>
  327. <view class="btns">
  328. <view v-if="!goodsIds.length" class="right_now r_disable">{{
  329. isCarOrBuy == 2 ? "立即购买" : "加入购物车"
  330. }}</view>
  331. <view v-else class="right_now" @click="rightNowBuy()"
  332. >{{ isCarOrBuy == 2 ? "立即购买" : "加入购物车" }}
  333. </view>
  334. </view>
  335. </view>
  336. </view>
  337. </u-popup>
  338. </view>
  339. </template>
  340. <script>
  341. import courseModule from "@/components/course/courseModule.vue";
  342. import courseChapter from "@/components/course/courseChapter.vue";
  343. import courseSection from "@/components/course/courseSection.vue";
  344. import handoutsBox from "@/components/course/handoutsBox.vue";
  345. import courseTree from "@/components/course/courseTree.vue";
  346. import { mapGetters, mapMutations } from "vuex";
  347. export default {
  348. components: {
  349. courseModule,
  350. courseChapter,
  351. courseSection,
  352. handoutsBox,
  353. courseTree,
  354. },
  355. data() {
  356. return {
  357. id: 0,
  358. list: [],
  359. menuIndex: [],
  360. current: 0,
  361. detail: {},
  362. courseList: [],
  363. menuList: [],
  364. freeMenuList: [],
  365. startStatus: false,
  366. playbackRate: [1.0],
  367. isAllowSeek: "no",
  368. vid: "",
  369. autoplay: true,
  370. listenConfigList: [],
  371. listenSecond: 0,
  372. isFirstEnter: true, //是否首次进入
  373. timer: null,
  374. businessData: {},
  375. startTime: 0,
  376. bugCourseModel: false, // 弹窗
  377. hadBuyCourse: {}, // 已购买课程信息
  378. goodsTeacher: [],
  379. teaIndex: 0,
  380. States: { 0: 0 },
  381. goodsType: 1, // 1视频2题库 3补考 4前培 6直播
  382. toggleSkuShow: false,
  383. skuItem: {},
  384. isCarOrBuy: 1, // 1加入购物车 2立即购买
  385. specList: [], // 规格列表
  386. checkedAttrs: [],
  387. selectGoodIndex: 0,
  388. specAttrPriceList: [],
  389. options: {},
  390. courseId: "",
  391. };
  392. },
  393. computed: {
  394. ...mapGetters([
  395. "userInfo",
  396. "goodsAuditionConfigIdList",
  397. "playSectionId",
  398. "hideBuyState",
  399. ]),
  400. allPrice() {
  401. if (!this.specList.length) return 0;
  402. let allPrice = this.specList.slice(-1)[0].specAttrList.reduce((a, b) => {
  403. if (b.check) {
  404. return a + b.standPrice;
  405. }
  406. return a;
  407. }, 0);
  408. return this.toFixed(allPrice);
  409. },
  410. goodsIds() {
  411. if (!this.specList.length) return [];
  412. return this.specList
  413. .slice(-1)[0]
  414. .specAttrList.filter((e) => e.check)
  415. .map((e) => e.goodsId);
  416. },
  417. isSingleChoice() {
  418. if (!this.specAttrPriceList.length) {
  419. return false;
  420. }
  421. return this.specAttrPriceList[0].specialGoods;
  422. },
  423. disCode() {
  424. return this.options.distributionCode;
  425. },
  426. isJx() {
  427. // 8 讲义资料商品
  428. return this.goodsType == 8;
  429. },
  430. },
  431. onLoad(option) {
  432. if (option.scene) {
  433. // scene 生成二维码扫码进来的
  434. let optObj = {};
  435. let arrs = decodeURIComponent(option.scene).split("&");
  436. for (let i = 0; i < arrs.length; i++) {
  437. optObj[arrs[i].split("=")[0]] = arrs[i].split("=")[1];
  438. }
  439. this.id = optObj.id;
  440. this.goodsType = optObj.goodsType || optObj.gt;
  441. console.log("optObj.sc:", optObj);
  442. uni.setStorageSync("newUser_sc", optObj.sc);
  443. uni.setStorageSync("shareActivityCode", optObj.sac);
  444. if (optObj.sac && this.$method.isLogin()) {
  445. this.editShareActivityCode();
  446. }
  447. } else {
  448. // 小程序正常跳转的
  449. // this.id => goodsId
  450. this.id = option.id;
  451. this.goodsType = option.goodsType || option.gt;
  452. this.options = option;
  453. if (option.sac) {
  454. uni.setStorageSync("shareActivityCode", option.sac);
  455. if (this.$method.isLogin()) {
  456. //已登录
  457. this.editShareActivityCode();
  458. this.getIsBuy(); // 判断是否已经购买过该课程
  459. }
  460. }
  461. }
  462. this.disCode ? this.getFxDetail() : this.getDetail();
  463. // 非讲义商品
  464. if (!this.isJx) {
  465. this.goodsCourseList();
  466. this.appCommonGoodsCourseModuleFreeExamList();
  467. } else {
  468. this.list = [
  469. {
  470. name: "资料目录",
  471. value: 3,
  472. },
  473. ];
  474. this.current = 3;
  475. }
  476. // #ifdef MP-WEIXIN
  477. wx.showShareMenu({
  478. withShareTicket: true,
  479. menus: ["shareAppMessage", "shareTimeline"],
  480. });
  481. // #endif
  482. },
  483. onUnload(option) {
  484. this.$store.commit("setPlaySectionId", { playSectionId: 0 });
  485. //移除所有的事件监听器
  486. uni.$off();
  487. },
  488. // 分享到朋友圈
  489. onShareTimeline() {
  490. return {
  491. title: this.detail.goodsName,
  492. query: "id=" + this.id,
  493. imageUrl: this.$method.splitImgHost(this.detail.coverUrl),
  494. };
  495. },
  496. // 分享给朋友
  497. onShareAppMessage() {
  498. return {
  499. title: this.detail.goodsName,
  500. path:
  501. `/pages3/course/detail?id=` + this.id + "&goodsType=" + this.goodsType,
  502. imageUrl: this.$method.splitImgHost(this.detail.coverUrl),
  503. };
  504. },
  505. mounted() {
  506. let self = this;
  507. uni.$on("getSection", (item) => {
  508. console.log("🚀 ~ file: detail.vue:578 ~ uni.$on ~ item:", item);
  509. //播放试听
  510. self.listenSecond = 0;
  511. for (var itemChild of self.listenConfigList) {
  512. if (
  513. item.sectionId == (itemChild.sectionId || itemChild.menuId) &&
  514. item.courseId == itemChild.courseId
  515. ) {
  516. if (itemChild.auditionMinute > 0) {
  517. // self.listenSecond = itemChild.auditionMinute *60 //试听秒数
  518. self.listenSecond = itemChild.auditionMinute; //试听秒数 auditionMinute调整为秒单位
  519. }
  520. }
  521. }
  522. console.log(self.listenSecond, "self.listenSecond");
  523. if (self.listenSecond > 0) {
  524. if (self.timer) {
  525. clearInterval(self.timer);
  526. }
  527. if (item.recordingUrl) {
  528. self.vid = item.recordingUrl;
  529. if (this.player) {
  530. this.player.changeVid(this.vid);
  531. return;
  532. }
  533. //切换视频
  534. // #ifdef H5
  535. this.loadPlayerScript(this.loadPlayer);
  536. // #endif
  537. // #ifdef MP-WEIXIN
  538. this.player = self.selectComponent("#player");
  539. // #endif
  540. } else {
  541. self.$u.toast("地址错误,无法播放");
  542. }
  543. self.startStatus = true;
  544. self.startTime = 0;
  545. } else {
  546. self.$u.toast("试听配置错误");
  547. }
  548. });
  549. this.updateChapterOpen(true);
  550. },
  551. methods: {
  552. ...mapMutations(["updateChapterOpen"]),
  553. itemWidth() {
  554. return 100 / this.list.length + "%";
  555. },
  556. // 修改用户活动邀请码
  557. editShareActivityCode() {
  558. console.log("修改用户活动邀请码");
  559. this.$http({
  560. url: "/app/user/edit/shareActivityCode",
  561. method: "post",
  562. data: {
  563. shareActivityCode: uni.getStorageSync("shareActivityCode"),
  564. },
  565. }).then((res) => {
  566. if (res.data.code == 200) {
  567. }
  568. });
  569. },
  570. appCommonGoodsCourseModuleFreeExamList() {
  571. // url: '/app/common/goods/course/moduleFreeExamList/'+data,
  572. this.$api.appCommonGoodsCourseModuleFreeExamList(this.id).then((res) => {
  573. if (res.data.data.length) {
  574. this.freeMenuList = res.data.data;
  575. this.list = [
  576. {
  577. name: "课程介绍",
  578. value: 0,
  579. },
  580. {
  581. name: "课程目录",
  582. value: 1,
  583. },
  584. {
  585. name: "赠送",
  586. value: 2,
  587. },
  588. ];
  589. } else {
  590. this.list = [
  591. {
  592. name: "课程介绍",
  593. value: 0,
  594. },
  595. {
  596. name: "课程目录",
  597. value: 1,
  598. },
  599. ];
  600. }
  601. console.log(this.list);
  602. });
  603. },
  604. selectGoodType(index) {
  605. if (index == this.selectGoodIndex) {
  606. return;
  607. }
  608. this.selectGoodIndex = index;
  609. this.changeData();
  610. },
  611. select(val) {
  612. val.check = !val.check;
  613. },
  614. checkboxChange(val) {
  615. if (!this.isSingleChoice) return;
  616. this.specList.slice(-1)[0].specAttrList.forEach((ele) => {
  617. if (val.name != ele.specAttributeId) {
  618. ele.check = false;
  619. }
  620. });
  621. },
  622. courseBusiness() {
  623. // url: '/app/common/course/business/'+data,
  624. this.$api.courseBusiness(this.detail.businessId).then((res) => {
  625. this.businessData = res.data.data;
  626. });
  627. },
  628. toFixed(number) {
  629. if (number > 0) {
  630. return number.toFixed(2);
  631. } else {
  632. return "0.00";
  633. }
  634. },
  635. onStateChange(newstate, oldstate) {
  636. if (newstate.detail.newstate == "playing") {
  637. //开始播放
  638. if (this.timer) {
  639. clearInterval(this.timer);
  640. }
  641. this.timer = setInterval(this.timeEvent, 1500); //定时器
  642. }
  643. },
  644. closePlay() {
  645. this.$store.commit("setPlaySectionId", { playSectionId: 0 });
  646. this.vid = "";
  647. this.startStatus = false;
  648. },
  649. timeEvent() {
  650. let self = this;
  651. var polyvPlayerContext = this.selectComponent("#playerVideo");
  652. if (polyvPlayerContext != null) {
  653. let PlayCurrentTime = polyvPlayerContext.getCurrentTime();
  654. if (PlayCurrentTime >= this.listenSecond) {
  655. polyvPlayerContext.stop();
  656. polyvPlayerContext.exitFullScreen();
  657. clearInterval(this.timer);
  658. this.timer = null;
  659. uni.showModal({
  660. title: "提示",
  661. content: "试听结束,购买课程可学习全部",
  662. showCancel: false,
  663. success: function (resst) {
  664. self.closePlay();
  665. },
  666. });
  667. }
  668. }
  669. },
  670. openCourse(item) {
  671. this.courseId = item.courseId;
  672. item.down = !item.down;
  673. if (!item.down && item.menuList.length == 0) {
  674. this.getMenuList(item);
  675. }
  676. },
  677. addShopCart(goodsIds) {
  678. if (!Array.isArray(goodsIds)) {
  679. goodsIds = [goodsIds];
  680. }
  681. this.$api
  682. .addCart({
  683. goodsIds: goodsIds,
  684. choiceStatus: 1,
  685. })
  686. .then((res) => {
  687. if (res.data.code == 200) {
  688. uni.setStorageSync("updateCart", 1); //提醒刷新购物车
  689. uni.showToast({
  690. title: "添加成功",
  691. });
  692. } else {
  693. this.$u.toast(res.data.msg);
  694. }
  695. });
  696. },
  697. goodsCourseList() {
  698. // url: '/app/common/goods/course/list/'+ data,
  699. this.$api.goodsCourseList(this.id).then((res) => {
  700. if (res.data.code == 200) {
  701. for (let i = 0; i < res.data.rows.length; i++) {
  702. let item = res.data.rows[i];
  703. item.down = true;
  704. item.menuList = [];
  705. }
  706. this.courseList = res.data.rows;
  707. this.getFirstCourse();
  708. // 不同
  709. if (this.goodsType == 1) {
  710. this.getCourseTeacher(res.data.rows);
  711. }
  712. }
  713. });
  714. },
  715. /**
  716. * 获取第一个有模块或者章的课程
  717. */
  718. async getFirstCourse() {
  719. for (let i = 0; i < this.courseList.length; i++) {
  720. let menuIndexOrFalse = await this.getCourseMenus(this.courseList[i]);
  721. if (menuIndexOrFalse !== false) {
  722. this.menuIndex = [i, menuIndexOrFalse];
  723. this.openCourse(this.courseList[i]);
  724. break;
  725. }
  726. }
  727. },
  728. getCourseMenus(item) {
  729. return new Promise((resolve) => {
  730. // url: '/app/common/course/menuList',
  731. this.$api.menuList({ courseId: item.courseId }).then((res) => {
  732. if (res.data.code == 200) {
  733. for (let i = 0; i < res.data.rows.length; i++) {
  734. if (res.data.rows[i].type == 1 || res.data.rows[i].type == 2) {
  735. resolve(i);
  736. break;
  737. }
  738. }
  739. }
  740. });
  741. });
  742. },
  743. getCourseTeacher(rows) {
  744. //获取商品双师资模板
  745. this.$api
  746. .getGoodsCourseTeacher({
  747. goodsId: this.id,
  748. })
  749. .then((res1) => {
  750. if (res1.data.data && res1.data.data.length > 0) {
  751. //课程老师模板
  752. let teacherTel = res1.data.data;
  753. //商品课程
  754. let courses = rows;
  755. teacherTel.forEach((tea) => {
  756. let dataList = [];
  757. let teacherList = [];
  758. courses.forEach((item) => {
  759. let data = tea.courseList.filter(
  760. (x) => x.courseId == item.courseId
  761. );
  762. if (data && data.length > 0) {
  763. dataList.push(item);
  764. teacherList = tea.courseList;
  765. }
  766. });
  767. let result = {
  768. teaList: teacherList,
  769. courseList: dataList,
  770. };
  771. this.goodsTeacher.push(result);
  772. });
  773. if (this.goodsTeacher && this.goodsTeacher.length > 0) {
  774. let courseIds = [];
  775. this.goodsTeacher.forEach((item) => {
  776. item.courseList.forEach((course) => {
  777. courseIds.push(course.courseId);
  778. });
  779. });
  780. if (courseIds.length > 0) {
  781. courses.forEach((item) => {
  782. if (!courseIds.includes(item.courseId)) {
  783. let data = {
  784. teaList: [],
  785. courseList: [],
  786. };
  787. data.courseList.push(item);
  788. this.goodsTeacher.push(data);
  789. }
  790. });
  791. }
  792. this.goodsTeacher.forEach((item) => {
  793. if (item.courseList && item.courseList.length > 0) {
  794. item.courseList[0].show = 1;
  795. }
  796. });
  797. }
  798. } else {
  799. //没有双师资模板
  800. rows.forEach((item) => {
  801. item.show = 1;
  802. let data = {
  803. teaList: [],
  804. courseList: [],
  805. };
  806. data.courseList.push(item);
  807. this.goodsTeacher.push(data);
  808. });
  809. console.log(this.goodsTeacher, "this.goodsTeacher");
  810. }
  811. });
  812. },
  813. //切换老师
  814. switchTeacher(data, tindex, gTindex) {
  815. // console.log(data,'data');
  816. this.States[gTindex] = tindex;
  817. this.teaIndex = tindex;
  818. this.goodsTeacher.forEach((item, index) => {
  819. if (item.teaList && item.teaList.length > 0) {
  820. let list = item.teaList.filter((x) => x.courseId == data.courseId);
  821. if (list && list.length > 0) {
  822. item.courseList.forEach((course, courseIndex) => {
  823. if (course.courseId == data.courseId) {
  824. this.$set(
  825. this.goodsTeacher[index].courseList[courseIndex],
  826. "show",
  827. 1
  828. );
  829. } else {
  830. this.$set(
  831. this.goodsTeacher[index].courseList[courseIndex],
  832. "show",
  833. 0
  834. );
  835. }
  836. });
  837. }
  838. }
  839. });
  840. console.log("切换后的this.goodsTeacher, ", this.goodsTeacher);
  841. },
  842. getMenuList(item) {
  843. this.$api.menuList({ courseId: item.courseId }).then((res) => {
  844. if (res.data.code == 200) {
  845. for (let i = 0; i < res.data.rows.length; i++) {
  846. let item = res.data.rows[i];
  847. item.down = true;
  848. item.id = item.menuId;
  849. item.name = item.menuName;
  850. }
  851. item.menuList = res.data.rows;
  852. }
  853. });
  854. },
  855. paramsFn() {
  856. return {
  857. courseId: this.courseId,
  858. listenConfigList: this.listenConfigList,
  859. };
  860. },
  861. getFxDetail() {
  862. let self = this;
  863. let sectionIdList = [];
  864. this.$api
  865. .fxGoodsDetail({
  866. goodsId: this.id,
  867. disCode: this.disCode,
  868. })
  869. .then((res) => {
  870. if (res.data.code == 200) {
  871. if (res.data.data) {
  872. if (res.data.data.mobileDetailHtml) {
  873. res.data.data.mobileDetailHtml =
  874. res.data.data.mobileDetailHtml.replace(
  875. /<img/gi,
  876. '<img style="max-width:100%;"'
  877. );
  878. }
  879. self.detail = res.data.data;
  880. this.courseBusiness();
  881. if (self.detail.goodsAuditionConfig) {
  882. self.listenConfigList = JSON.parse(
  883. self.detail.goodsAuditionConfig
  884. );
  885. console.log(self.listenConfigList, "self.listenConfigList");
  886. for (var itemChild of self.listenConfigList) {
  887. sectionIdList.push(itemChild.sectionId); //存储试听节ID
  888. }
  889. self.$store.commit("setGoodsAuditionConfigIdList", {
  890. goodsAuditionConfigIdList: sectionIdList,
  891. });
  892. }
  893. }
  894. }
  895. });
  896. },
  897. // 获取课程详情
  898. getDetail() {
  899. let self = this;
  900. let sectionIdList = [];
  901. this.$api.commonGoodsDetail(this.id).then((res) => {
  902. if (res.data.code == 200) {
  903. if (res.data.data) {
  904. if (res.data.data.mobileDetailHtml) {
  905. res.data.data.mobileDetailHtml =
  906. res.data.data.mobileDetailHtml.replace(
  907. /<img/gi,
  908. '<img style="max-width:100%;"'
  909. );
  910. }
  911. self.detail = res.data.data;
  912. console.log(self.detail, 789);
  913. this.courseBusiness();
  914. if (self.detail.goodsAuditionConfig) {
  915. self.listenConfigList = JSON.parse(
  916. self.detail.goodsAuditionConfig
  917. );
  918. console.log(self.listenConfigList, "self.listenConfigList");
  919. for (var itemChild of self.listenConfigList) {
  920. sectionIdList.push(itemChild.sectionId); //存储试听节ID
  921. }
  922. self.$store.commit("setGoodsAuditionConfigIdList", {
  923. goodsAuditionConfigIdList: sectionIdList,
  924. });
  925. }
  926. }
  927. }
  928. });
  929. },
  930. toConfirmList(id) {
  931. uni.navigateTo({
  932. url: "/pages2/order/confirm_list?id=" + id + this.addParam(),
  933. });
  934. },
  935. addParam(str = "") {
  936. if (this.disCode) {
  937. str += "&distributionCode=" + this.disCode;
  938. }
  939. if (this.options.linkCode) {
  940. str += "&linkCode=" + this.options.linkCode;
  941. }
  942. return str;
  943. },
  944. buy() {
  945. if (this.$method.isGoLogin()) {
  946. return;
  947. }
  948. // 判断有没有规格选择
  949. if (this.detail.specTemplateId) {
  950. this.isCarOrBuy = 2;
  951. this.getSpecDetail();
  952. return;
  953. }
  954. this.toConfirmList(this.id);
  955. },
  956. drawBuy() {
  957. if (!this.$method.isLogin()) {
  958. uni.navigateTo({
  959. url: "/pages4/login/login?isBack=" + true + "&isAct=1",
  960. });
  961. return;
  962. }
  963. this.$api
  964. .drowActGoods({
  965. url: location.href,
  966. goodsList: [this.detail],
  967. sellerName: this.options.sale,
  968. })
  969. .then((res) => {
  970. if (res.data.code == 200) {
  971. // this.$u.toast("领取成功");
  972. uni.showModal({
  973. title: "提示",
  974. content: "领取成功,是否现在去做题?",
  975. cancelText: "取消",
  976. confirmText: "确定",
  977. success: (res) => {
  978. if (res.confirm) {
  979. uni.switchTab({
  980. url: "/pages/questionBank/index",
  981. });
  982. }
  983. },
  984. });
  985. } else {
  986. this.$u.toast(res.data.msg);
  987. }
  988. });
  989. },
  990. addCart() {
  991. if (this.$method.isGoLogin()) {
  992. return;
  993. }
  994. // 判断有没有规格选择
  995. if (this.detail.specTemplateId) {
  996. this.isCarOrBuy = 1;
  997. this.getSpecDetail();
  998. return;
  999. }
  1000. this.addShopCart(this.id);
  1001. },
  1002. getSpecDetail() {
  1003. this.checkedAttrs = [];
  1004. let data = {};
  1005. let url = `/app/common/spec/${this.detail.specTemplateId}`;
  1006. if (this.disCode) {
  1007. url = "/app/common/distribution/spec";
  1008. data = {
  1009. disCode: this.disCode,
  1010. specTemplateId: this.detail.specTemplateId,
  1011. };
  1012. }
  1013. this.$http({
  1014. url,
  1015. method: "get",
  1016. noToken: true,
  1017. data,
  1018. }).then((res) => {
  1019. let data = res.data.data;
  1020. if (data) {
  1021. this.toggleSkuShow = true;
  1022. this.specAttrPriceList = data.specAttrPriceList;
  1023. this.specList = this.changeData(data.specList || []);
  1024. } else {
  1025. if (this.isCarOrBuy == 1) {
  1026. // 加入购物车
  1027. this.addShopCart(this.id);
  1028. } else {
  1029. this.toConfirmList(this.id);
  1030. }
  1031. this.closePop();
  1032. }
  1033. });
  1034. },
  1035. changeData(data = this.specList) {
  1036. let len = data.length;
  1037. if (!len) return [];
  1038. data[len - 1].specAttrList.forEach((e, i) => {
  1039. e.check = e.check || false;
  1040. let id = e.specAttributeId;
  1041. if (len > 1) {
  1042. id =
  1043. data[0].specAttrList[this.selectGoodIndex].specAttributeId +
  1044. "," +
  1045. id;
  1046. }
  1047. let item = this.specAttrPriceList.find((e) => e.specAttrIds == id);
  1048. if (item) {
  1049. e.standPrice = item.standPrice;
  1050. e.goodsId = item.goodsId;
  1051. } else {
  1052. e.goodsId = null;
  1053. }
  1054. });
  1055. // data.forEach((item, index) => {
  1056. // if (index == len - 1) {
  1057. // item.specAttrList.forEach((e, i) => {
  1058. // e.check = false
  1059. // })
  1060. // }
  1061. // })
  1062. return data;
  1063. },
  1064. change(index) {
  1065. this.current = index;
  1066. },
  1067. toShopcar() {
  1068. uni.navigateTo({
  1069. url: "/pages4/shopping/shoppingCart",
  1070. });
  1071. },
  1072. getIsBuy() {
  1073. this.$http({
  1074. url: "/order/buyGoodsNotExpired",
  1075. method: "get",
  1076. data: { goodsId: this.id },
  1077. }).then((res) => {
  1078. if (res.data.code == 200) {
  1079. if (res.data.data) {
  1080. // 有data返回是已经购买过的课程
  1081. this.hadBuyCourse = res.data.data;
  1082. this.bugCourseModel = true;
  1083. }
  1084. }
  1085. });
  1086. },
  1087. changeKown() {
  1088. this.bugCourseModel = false;
  1089. },
  1090. async toStudy() {
  1091. let item = this.hadBuyCourse;
  1092. if (item.goodsType == 6) {
  1093. // 进入直播课
  1094. this.toLive(item);
  1095. return;
  1096. }
  1097. // /course/goodsRebuildStatus查询用户商品重修状态
  1098. let rebuildStatus = await this.courseGoodsRebuildStatus(
  1099. item.goodsId,
  1100. item.gradeId
  1101. );
  1102. if (rebuildStatus == 0) {
  1103. this.$navTo.togo("/pages2/learn/details", {
  1104. gradeId: item.gradeId,
  1105. goodsId: item.goodsId,
  1106. orderGoodsId: item.orderGoodsId,
  1107. });
  1108. return;
  1109. }
  1110. this.$method.checkLock().then((res) => {
  1111. this.$http({
  1112. url: "/course/courseList",
  1113. method: "get",
  1114. data: {
  1115. pageNum: 1,
  1116. pageSize: 1,
  1117. goodsId: item.goodsId,
  1118. gradeId: item.gradeId,
  1119. orderGoodsId: item.orderGoodsId,
  1120. },
  1121. }).then((res) => {
  1122. if (res.data.code == 200) {
  1123. if (res.data.total > 1) {
  1124. // this.$navTo.togo(`/pages2/wd/course?id=${item.goodsId}&gid=${item.gradeId}&orderGoodsId=${item.orderGoodsId}`);
  1125. uni.navigateTo({
  1126. url: `/pages3/polyv/detail?id=''&goodsId=${item.goodsId}&orderGoodsId=${item.orderGoodsId}&gradeId=${item.gradeId}`,
  1127. });
  1128. } else if (res.data.total == 1) {
  1129. uni.navigateTo({
  1130. url: `/pages3/polyv/detail?id=${res.data.rows[0].courseId}&goodsId=${item.goodsId}&orderGoodsId=${item.orderGoodsId}&gradeId=${item.gradeId}`,
  1131. });
  1132. } else {
  1133. uni.showToast({
  1134. icon: "none",
  1135. title: "暂无可观看的视频课程",
  1136. });
  1137. }
  1138. }
  1139. });
  1140. });
  1141. },
  1142. toLive(item) {
  1143. this.$api
  1144. .courseCourseList({
  1145. pageNum: 1,
  1146. pageSize: 1,
  1147. goodsId: item.goodsId,
  1148. gradeId: 0,
  1149. orderGoodsId: item.orderGoodsId,
  1150. })
  1151. .then((res) => {
  1152. if (res.data.code == 200) {
  1153. if (res.data.total > 1) {
  1154. // uni.navigateTo({
  1155. // url:'/pages5/liveDetail/course?orderGoodsId='+item.orderGoodsId+'&goodsId='+item.goodsId+'&gradeId=0'
  1156. // })
  1157. uni.navigateTo({
  1158. url:
  1159. "/pages3/live/detail?orderGoodsId=" +
  1160. item.orderGoodsId +
  1161. "&goodsId=" +
  1162. item.goodsId +
  1163. '&gradeId=0&courseId=""',
  1164. });
  1165. } else if (res.data.total == 1) {
  1166. uni.navigateTo({
  1167. url:
  1168. "/pages3/live/detail?orderGoodsId=" +
  1169. item.orderGoodsId +
  1170. "&goodsId=" +
  1171. item.goodsId +
  1172. "&gradeId=0&courseId=" +
  1173. res.data.rows[0].courseId,
  1174. });
  1175. } else {
  1176. uni.showToast({
  1177. icon: "none",
  1178. title: "暂无可观看的直播课程",
  1179. });
  1180. }
  1181. }
  1182. });
  1183. },
  1184. /**
  1185. * @param {Object} goodsId 商品id
  1186. * 查询商品重修状态
  1187. */
  1188. courseGoodsRebuildStatus(goodsId, gradeId) {
  1189. return new Promise((resolve) => {
  1190. this.$http({
  1191. url: "/course/goodsRebuildStatus",
  1192. method: "get",
  1193. data: {
  1194. goodsId: goodsId,
  1195. gradeId: gradeId,
  1196. },
  1197. // noLoading: true,
  1198. // compleLoading: true, // 请求成功是否还要继续显示加载中
  1199. }).then((res) => {
  1200. resolve(res.data.data);
  1201. });
  1202. });
  1203. },
  1204. closePop() {
  1205. this.toggleSkuShow = false;
  1206. this.skuItem = {};
  1207. },
  1208. // 获取规格属性值对应的商品信息
  1209. getGoodsInfos(specAttrIds) {
  1210. this.$http({
  1211. url: "/app/common/attr/goods",
  1212. method: "get",
  1213. data: {
  1214. specTemplateId: this.detail.specTemplateId,
  1215. specAttrIds: specAttrIds.join(","),
  1216. },
  1217. noToken: true,
  1218. }).then((res) => {
  1219. if (res.data.code == 200) {
  1220. this.skuItem = res.data.data || {};
  1221. } else {
  1222. this.skuItem = {};
  1223. this.$u.toast("商品已下架, 请重新选择");
  1224. }
  1225. });
  1226. },
  1227. rightNowBuy() {
  1228. let goodsIds = [...new Set(this.goodsIds)];
  1229. this.$api.checkGoodsStatus({ goodsIds }).then((res) => {
  1230. if (res.data.code == 500) {
  1231. return this.$u.toast(res.data.msg);
  1232. }
  1233. if (this.isCarOrBuy == 1) {
  1234. // 加入购物车
  1235. this.addShopCart(goodsIds);
  1236. } else {
  1237. if (this.isSingleChoice) {
  1238. this.toConfirmList(goodsIds);
  1239. } else {
  1240. let data = [];
  1241. goodsIds.forEach((id) => {
  1242. data.push(this.specAttrPriceList.find((e) => e.goodsId == id));
  1243. });
  1244. this.$store.commit("setShoppingCartList", {
  1245. shoppingCartList: data,
  1246. });
  1247. this.$navTo.togo("/pages2/order/confirm_pay" + this.addParam("?"));
  1248. }
  1249. }
  1250. this.closePop();
  1251. });
  1252. },
  1253. loadPlayerScript(callback) {
  1254. if (!window.polyvPlayer) {
  1255. const myScript = document.createElement("script");
  1256. myScript.setAttribute(
  1257. "src",
  1258. "https://player.polyv.net/script/player.js"
  1259. );
  1260. myScript.onload = callback;
  1261. document.body.appendChild(myScript);
  1262. } else {
  1263. callback();
  1264. }
  1265. },
  1266. // 播放视频
  1267. loadPlayer() {
  1268. const polyvPlayer = window.polyvPlayer;
  1269. this.$api.polyvVideoSign(this.vid).then(async (res) => {
  1270. console.log("播放凭证res", res);
  1271. this.player = await polyvPlayer({
  1272. wrap: "#player",
  1273. width: "100%",
  1274. showLine: "off",
  1275. height: 218,
  1276. ban_history_time: "on",
  1277. vid: this.vid,
  1278. forceH5: true,
  1279. autoplay: this.autoplay,
  1280. speed: this.playbackRate,
  1281. teaser_show: 1,
  1282. tail_show: 1,
  1283. hideSwitchPlayer: true,
  1284. ts: res.data.data.ts,
  1285. sign: res.data.data.sign,
  1286. });
  1287. this.polyvPlayerContext = this.player;
  1288. });
  1289. },
  1290. },
  1291. provide() {
  1292. return {
  1293. paramsFn: this.paramsFn,
  1294. };
  1295. },
  1296. };
  1297. </script>
  1298. <style>
  1299. page {
  1300. background-color: #f2f2f2;
  1301. }
  1302. </style>
  1303. <style lang="scss" scope>
  1304. @import "./index.scss";
  1305. /deep/ {
  1306. .menuBox {
  1307. padding: 0;
  1308. }
  1309. }
  1310. .video_t2 {
  1311. font-size: 24rpx;
  1312. font-family: PingFang SC;
  1313. font-weight: 500;
  1314. color: #666666;
  1315. }
  1316. .video_t1 {
  1317. height: 80rpx;
  1318. color: #333333;
  1319. line-height: 80rpx;
  1320. font-size: 30rpx;
  1321. font-family: PingFang SC;
  1322. font-weight: bold;
  1323. color: #333333;
  1324. overflow: hidden;
  1325. text-overflow: ellipsis;
  1326. white-space: nowrap;
  1327. }
  1328. .video_t1_t {
  1329. display: flex;
  1330. flex-direction: column;
  1331. height: 80rpx;
  1332. color: #333333;
  1333. text-align: center;
  1334. align-items: center;
  1335. border-left: solid 1px #d6d6db;
  1336. }
  1337. .video_play {
  1338. position: absolute;
  1339. width: 95rpx;
  1340. height: 95rpx;
  1341. top: 0;
  1342. left: 0;
  1343. right: 0;
  1344. bottom: 0;
  1345. margin: auto;
  1346. }
  1347. .video_box {
  1348. position: relative;
  1349. }
  1350. .contents {
  1351. width: 100%;
  1352. height: 100%;
  1353. background-color: #ffffff;
  1354. margin-top: 16rpx;
  1355. overflow: hidden;
  1356. }
  1357. .cou_title {
  1358. padding: 24rpx 32rpx 40rpx 32rpx;
  1359. display: flex;
  1360. flex-direction: column;
  1361. justify-content: space-around;
  1362. }
  1363. .prices {
  1364. .price_word {
  1365. display: flex;
  1366. font-size: 44rpx;
  1367. font-weight: 800;
  1368. color: #fc3f3f;
  1369. margin-bottom: 8rpx;
  1370. view::before {
  1371. content: "¥";
  1372. font-size: 26rpx;
  1373. font-weight: bold;
  1374. }
  1375. }
  1376. .sale {
  1377. color: #999999;
  1378. font-size: 28rpx;
  1379. margin-left: 8rpx;
  1380. }
  1381. .price_line {
  1382. color: #999999;
  1383. font-size: 28rpx;
  1384. text-decoration: line-through;
  1385. font-weight: 400;
  1386. }
  1387. .free {
  1388. font-size: 32rpx;
  1389. }
  1390. }
  1391. // tab
  1392. .tabs {
  1393. // width: 100%;
  1394. height: 78rpx;
  1395. display: flex;
  1396. align-items: center;
  1397. justify-content: space-between;
  1398. background-color: #f2f7ff;
  1399. border-radius: 38rpx;
  1400. margin: 24rpx;
  1401. padding: 0rpx 5rpx;
  1402. .tab_item {
  1403. flex: 1;
  1404. height: 65rpx;
  1405. line-height: 65rpx;
  1406. font-size: 28rpx;
  1407. font-weight: bold;
  1408. border-radius: 32rpx;
  1409. text-align: center;
  1410. color: #333;
  1411. &.nactive {
  1412. color: #fff;
  1413. background-color: #3577e8;
  1414. }
  1415. }
  1416. // /deep/ .u-tabs {
  1417. // background:none!important;
  1418. // }
  1419. }
  1420. .courseName {
  1421. white-space: nowrap;
  1422. overflow: hidden;
  1423. text-overflow: ellipsis;
  1424. }
  1425. .videoBox {
  1426. background-color: #ffffff;
  1427. width: 100%;
  1428. /* height: 680rpx; */
  1429. z-index: 999;
  1430. }
  1431. .icon_up {
  1432. width: 32rpx;
  1433. height: 32rpx;
  1434. }
  1435. .courseItemBox {
  1436. background: #ffffff;
  1437. border-radius: 16rpx;
  1438. padding: 0 10rpx;
  1439. margin-bottom: 20rpx;
  1440. }
  1441. .courseItem {
  1442. height: 80rpx;
  1443. color: #333333;
  1444. font-size: 32rpx;
  1445. line-height: 80rpx;
  1446. font-weight: bold;
  1447. display: flex;
  1448. justify-content: space-between;
  1449. }
  1450. .content {
  1451. background-color: #ffffff;
  1452. width: 100%;
  1453. }
  1454. .btn2 {
  1455. width: 187rpx;
  1456. height: 79rpx;
  1457. line-height: 79rpx;
  1458. background: #fc3f3f;
  1459. border-radius: 40rpx;
  1460. text-align: center;
  1461. font-size: 24rpx;
  1462. }
  1463. .btn1 {
  1464. width: 187rpx;
  1465. height: 79rpx;
  1466. line-height: 79rpx;
  1467. background: #ffb102;
  1468. border-radius: 40rpx;
  1469. text-align: center;
  1470. margin-right: 11rpx;
  1471. font-size: 24rpx;
  1472. }
  1473. .wk_icon {
  1474. width: 24rpx;
  1475. height: 24rpx;
  1476. margin-right: 12rpx;
  1477. }
  1478. .noteTag,
  1479. .blackFont {
  1480. font-size: 26rpx;
  1481. font-family: PingFang SC;
  1482. font-weight: 400;
  1483. color: #999999;
  1484. align-items: center;
  1485. margin: 0 4rpx;
  1486. line-height: 60rpx;
  1487. }
  1488. .priceTag {
  1489. /* font-size: 30rpx;
  1490. font-family: PingFang SC;
  1491. font-weight: bold;
  1492. color: #FF2D55; */
  1493. width: 60rpx;
  1494. height: 40rpx;
  1495. line-height: 40rpx;
  1496. text-align: center;
  1497. border: 1rpx solid #333;
  1498. }
  1499. .titleTag {
  1500. font-size: 32rpx;
  1501. font-weight: bold;
  1502. color: #333333;
  1503. // margin-left: 8rpx;
  1504. }
  1505. .yearTag {
  1506. width: 80rpx;
  1507. height: 32rpx;
  1508. background: #ebf5ff;
  1509. border: 2rpx solid #007aff;
  1510. border-radius: 16rpx;
  1511. font-size: 24rpx;
  1512. color: #007aff;
  1513. text-align: center;
  1514. line-height: 32rpx;
  1515. }
  1516. .itemBox {
  1517. background: #ffffff;
  1518. box-shadow: 0rpx 10rpx 9rpx 1rpx rgba(165, 196, 239, 0.1);
  1519. border-radius: 24rpx;
  1520. width: 100%;
  1521. padding: 20rpx;
  1522. margin-bottom: 20rpx;
  1523. }
  1524. // 老师名字样式
  1525. .teacher_names {
  1526. display: flex;
  1527. padding-bottom: 15rpx;
  1528. border-bottom: 2rpx solid #f0f0f0;
  1529. .names {
  1530. padding: 6rpx 12rpx;
  1531. font-size: 26rpx;
  1532. color: #969696;
  1533. background: #f8f8f8;
  1534. border-radius: 8rpx;
  1535. margin-right: 10rpx;
  1536. &.nactive {
  1537. color: #3f8dfd;
  1538. background: #f2f7ff;
  1539. }
  1540. }
  1541. }
  1542. </style>