_id.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. <template>
  2. <ErrorPage404 v-if="!isExist"></ErrorPage404>
  3. <div v-else :class="mobile ? 'mobileMain' : 'mobileWeb'" :style="{marginTop: mainMarginTop}">
  4. <div class="learn-detail-wrapper" v-if="!mobile">
  5. <!--面包屑-->
  6. <el-breadcrumb class="learn-breadcrumb">
  7. <el-breadcrumb-item :to="{ path: '/learn' }">客栈学院</el-breadcrumb-item>
  8. <el-breadcrumb-item>课程详情</el-breadcrumb-item>
  9. </el-breadcrumb>
  10. <!--视频播放-->
  11. <div class="learn-video">
  12. <!--已购买-->
  13. <div class="purchased">
  14. <a :href="`${'/lv/'+sale_id}`" class="video">
  15. <img class="play" src="@/assets/img/learn/video@2x.png" alt="play">
  16. <img class="bg-img" :src="defaultImg" v-real-img="learnDetail.info.img" alt="">
  17. </a>
  18. <div class="intro">
  19. <div class="title">
  20. <p class="text">{{ learnDetail.info.title }}</p>
  21. <div class="collect-share">
  22. <span class="common" @click="collectFun">
  23. <img class="icon" v-if="collectObj.resultCode==1" src="@/assets/img/learn/collect1@2x.png" alt="collect"/>
  24. <img class="icon" v-else src="@/assets/img/learn/collect2@2x.png" alt="collect"/>
  25. <span class="txt" :style="{color: collectObj.resultCode==1 ? '#308EFF' : ''}">{{collectObj.resultCode==1 ? '已收藏' : '收藏'}}</span>
  26. </span>
  27. <span class="common">
  28. <img class="icon" src="@/assets/img/learn/share@2x.png" alt="share"/>
  29. <span class="txt">分享</span>
  30. </span>
  31. </div>
  32. </div>
  33. <div class="lectruer">
  34. {{ learnDetail.info.buy_num }}人学过<span class="line">|</span><span>老师:</span><span class="txt">{{ learnDetail.teacher.name }}</span>
  35. </div>
  36. <div class="price">
  37. <span class="new">¥{{ learnDetail.info.price.toFixed(2) }}</span><span class="old">原价¥{{ learnDetail.info.yprice.toFixed(2) }}</span>
  38. </div>
  39. <div class="btns">
  40. <div>
  41. <el-button type="primary" class="go-buy" v-if="!learnDetail.info.is_buy" @click="goBtn">
  42. <img class="icon" src="@/assets/img/learn/car@2x.png" alt="car"/>
  43. 立即购买
  44. </el-button>
  45. <el-button v-else @click="goBtn">继续学习</el-button>
  46. </div>
  47. <div class="brief">
  48. <span>{{ learnDetail.info.video_num }}集</span>
  49. <span>{{ learnDetail.info.total_time }}小时</span>
  50. <span>{{ learnDetail.info.view_num }}万阅读</span>
  51. <span>完结</span>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <div class="learn-content">
  58. <div class="con-left">
  59. <!--tab-->
  60. <div class="learn-tabs">
  61. <div class="tabs-item" :class="tabActive==0 ? 'active' :''" @click="tabActive=0">介绍</div>
  62. <div class="tabs-item" :class="tabActive==1 ? 'active' :''" @click="tabActive=1">目录</div>
  63. <div class="tabs-item" :class="tabActive==2 ? 'active' :''" @click="tabActive=2">公告</div>
  64. </div>
  65. <!--介绍-->
  66. <div class="introduction" v-show="tabActive==0">
  67. <img :src="defaultImg" v-real-img="learnDetail.content.video_img" alt="">
  68. <p v-html="learnDetail.content.content"></p>
  69. </div>
  70. <!--目录-->
  71. <div class="catalog" v-show="tabActive==1">
  72. <template v-if="learnDetail.video && learnDetail.video.length>0">
  73. <div class="catalog-item" v-for="(catalogItem, index) in learnDetail.video" :key="index">
  74. <span class="title">第{{ index+1 }}章 {{ catalogItem.video_name }}</span>
  75. <div>
  76. <template v-if="catalogItem.list && catalogItem.list.length>0">
  77. <a class="li" v-for="(item, i) in catalogItem.list" :key="i" :href="`${'/lv/'+sale_id}`">
  78. <div>
  79. <span class="is-charge" :class="item.checked==1 ? 'free' : 'charge'">{{ item.checked==1 ? '免费' : '收费' }}</span>
  80. <span class="txt">课时{{ i+1 }}:{{ item.video_name }}</span>
  81. </div>
  82. <div>
  83. <span class="is-publish publish">已发布</span>
  84. <span class="timer"><img src="@/assets/img/learn/play@2x.png" alt=""/>{{ item.m }}:{{ item.s }}</span>
  85. </div>
  86. </a>
  87. </template>
  88. <div v-else class="learn-detail-empty">
  89. <img src="@/assets/img/common/empty@2x.png" alt="empty">
  90. <span>暂无课程</span>
  91. </div>
  92. </div>
  93. </div>
  94. </template>
  95. <div class="learn-detail-empty" v-else>
  96. <img src="@/assets/img/common/empty@2x.png" alt="empty">
  97. <span>暂无目录</span>
  98. </div>
  99. </div>
  100. <!--公告-->
  101. <div class="introduction" v-show="tabActive==2">
  102. <div class="learn-detail-empty" v-if="!learnDetail.content.notice_msg">
  103. <img src="@/assets/img/common/empty@2x.png" alt="empty">
  104. <span>暂无公告</span>
  105. </div>
  106. <p v-else v-html="learnDetail.content.notice_msg"></p>
  107. </div>
  108. <!--常见问题-->
  109. <div class="questions">
  110. <h4 class="header-txt">常见问题</h4>
  111. <el-collapse v-model="collapseName">
  112. <el-collapse-item title="Q1: 本课程的价格是一次性的吗?" name="1">
  113. <div>A: 课程标价就是整个课程的价格,购买后观看本课程内所有章节视频不另外收费。</div>
  114. </el-collapse-item>
  115. <el-collapse-item title="Q2: 购买本课程提供所用软件吗?" name="2">
  116. <div>A: 客栈学院只提供课程教学,不提供软件销售和下载,请同学们自行安装好正版软件进行学习。</div>
  117. </el-collapse-item>
  118. <el-collapse-item title="Q3: 本课程有观看有效期吗?" name="3">
  119. <div>A: 课程不限有效期,购买成功即可随时观看。</div>
  120. </el-collapse-item>
  121. <el-collapse-item title="Q4: 本课程视频可以下载吗?" name="4">
  122. <div>A: 由于视频涉及版权问题,课程视频不支持下载。</div>
  123. </el-collapse-item>
  124. <el-collapse-item title="Q5: 本课程买了之后有售后服务吗?" name="5">
  125. <div>A: 购买完课程之后可以加售后答疑微信,课程学习过程中会有资料发送、答疑解惑等售后服务内容。</div>
  126. </el-collapse-item>
  127. </el-collapse>
  128. </div>
  129. </div>
  130. <div class="con-right">
  131. <!--讲师-->
  132. <div class="r-lectruer">
  133. <div class="lectruer-img">
  134. <span class="l-img">
  135. <img :src="defaultImg" v-real-img="learnDetail.teacher.img" :alt="learnDetail.teacher.name">
  136. <span>讲师</span>
  137. </span>
  138. <span class="name">{{ learnDetail.teacher.name }}</span>
  139. <span class="job">{{ learnDetail.teacher.op }}</span>
  140. </div>
  141. <p class="lectruer-info">{{ learnDetail.teacher.content }}</p>
  142. </div>
  143. <!--课程咨询-->
  144. <div class="class-consult">
  145. <h4 class="header-txt" style="font-size:14px;">课程咨询</h4>
  146. <div class="consult">
  147. <div class="show-ewm">
  148. <el-button><img src=@/assets/img/learn/consult@2x.png alt="进群学习"/>进群学习</el-button>
  149. <img class="ewm" :src="learnDetail.content.ewm"/>
  150. </div>
  151. <p class="info" v-html="learnDetail.content.content"></p>
  152. </div>
  153. </div>
  154. <!--课程学习-->
  155. <!-- <div class="course-learn">
  156. <h4 class="header-txt" style="font-size:14px;">127人学习了该课程</h4>
  157. <ul>
  158. <li>
  159. <img src='@/assets/img/learn/video@2x.png' alt="海伦"/>
  160. <span>海伦</span>
  161. </li>
  162. <li>
  163. <img src='@/assets/img/learn/video@2x.png' alt="海伦"/>
  164. <span>海伦</span>
  165. </li>
  166. <li>
  167. <img src='@/assets/img/learn/video@2x.png' alt="海伦"/>
  168. <span>海伦</span>
  169. </li>
  170. <li>
  171. <img src='@/assets/img/learn/video@2x.png' alt="海伦"/>
  172. <span>海伦</span>
  173. </li>
  174. </ul>
  175. </div> -->
  176. </div>
  177. </div>
  178. </div>
  179. <div class="learn-detail-wrapper-mobile" v-else>
  180. 移动端详情
  181. </div>
  182. </div>
  183. </template>
  184. <script>
  185. import { mapState } from "vuex"
  186. import DealSeoDetail from "@/components/learn/dealSeoDetail"
  187. import qs from "qs"
  188. import ErrorPage404 from "@/components/error_page/404.vue"
  189. export default {
  190. name: 'SeoLearnDetail',
  191. data () {
  192. return {
  193. baseUrl: '',
  194. isWeixinApp: true,
  195. collapseName: 1,
  196. tabActive: 0,
  197. defaultImg: require('@/assets/img/common/empty@2x.png')
  198. }
  199. },
  200. components: {
  201. ErrorPage404
  202. },
  203. head() {
  204. const {
  205. title = "",
  206. keyword = "",
  207. description = "",
  208. h1 = "",
  209. canonical = "",
  210. metaLocation
  211. } = this.head || {}
  212. let obj = {
  213. title: title,
  214. meta: [{
  215. name: "keywords",
  216. content: keyword
  217. }, {
  218. name: "description",
  219. content: description
  220. }, {
  221. name: "h1",
  222. content: h1
  223. }, {
  224. name: "viewport",
  225. content: "width=device-width, initial-scale=1.0, viewport-fit=cover"
  226. }],
  227. // 引入三方资源
  228. link: [
  229. {rel: "canonical", href: canonical},
  230. // {rel: "stylesheet", href: "https://g.alicdn.com/de/prismplayer/2.9.13/skins/default/aliplayer-min.css"}
  231. ],
  232. script: [
  233. // { src: "https://g.alicdn.com/de/prismplayer/2.9.13/aliplayer-min.js" }
  234. ]
  235. }
  236. if (metaLocation) {
  237. obj.meta.push({name: "location", content: metaLocation})
  238. }
  239. return obj
  240. },
  241. computed: {
  242. ...mapState(["deviceType"]),
  243. showWxHeader () {
  244. return !this.deviceType.app && !this.isWeixinApp &&
  245. (this.deviceType.android || this.deviceType.ios)
  246. },
  247. mainMarginTop () {
  248. if (this.mobile && this.showWxHeader) {
  249. return '0 !important'
  250. } else if (this.mobile) {
  251. return '0px !important'
  252. } else {
  253. return '20px !important'
  254. }
  255. },
  256. },
  257. async asyncData ({...params}) {
  258. let dealDataObj = new DealSeoDetail(params)
  259. let result = await dealDataObj.dealData()
  260. console.log('打印异步数据看看',result)
  261. return {
  262. ...result
  263. }
  264. },
  265. mounted () {
  266. this.baseUrl = this.$store.state.domainConfig.siteUrl
  267. this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1
  268. },
  269. methods: {
  270. // 是否收藏
  271. collectFun(){
  272. let path = location.pathname // "/l/68"
  273. let reg = /^\/l\/\d+$/g
  274. let saleId = ''
  275. if(reg.test(path)){
  276. saleId = path.split('/l/')[1]
  277. }
  278. let params = {
  279. type: '100',
  280. item_id: saleId || '999'
  281. }
  282. if(this.collectObj.resultCode==1){
  283. this.$axios.$post('/uapi/collection/del', params).then(res => {
  284. let { data, status, info } = res
  285. if(status === 1){
  286. this.collectObj.resultCode = 0
  287. }
  288. })
  289. }else{
  290. this.$axios.$post('/uapi/collection/add', params).then(res => {
  291. let { data, status, info } = res
  292. if(status === 1){
  293. this.collectObj.resultCode = 1
  294. }
  295. })
  296. }
  297. },
  298. /**
  299. * 点击购买:
  300. * 跳转共用支付界面
  301. */
  302. goBtn () {
  303. // 立即购买
  304. if(!this.learnDetail.info.is_buy){
  305. const query = {
  306. product_type: 505,
  307. product_id: this.sale_id,
  308. next: location.href + '?act=pay'
  309. }
  310. if (!this.userinfo || !this.userinfo.nickname) {
  311. // 未登录时 => 去登录
  312. if (this.deviceType.ios || this.deviceType.android) {
  313. window.location.href = "proginn://login?backToPage=true";
  314. } else {
  315. window.location.href = this.baseUrl + "/?loginbox=show&next=" + encodeURIComponent(location.href)
  316. }
  317. } else {
  318. // 已登录,跳转支付
  319. if (this.deviceType.ios || this.deviceType.android) {
  320. window.location.href = "proginn://pay?" + qs.stringify(query)
  321. } else {
  322. window.location.href = this.baseUrl + "/pay?" + qs.stringify(query)
  323. }
  324. }
  325. // 继续学习
  326. }else {
  327. window.location.href = '/lv/'+ this.sale_id
  328. }
  329. }
  330. }
  331. }
  332. </script>
  333. <style lang="scss" scoped>
  334. @import "@/assets/css/learn/detail/_id.scss";
  335. </style>
  336. <style lang="scss">
  337. .el-collapse-item__header {
  338. background: #f4f5f9;
  339. padding-left: 16px;
  340. margin-bottom: 12px;
  341. }
  342. .el-collapse-item__content {
  343. padding-bottom: 12px;
  344. }
  345. .learn-detail-empty {
  346. display: flex;
  347. flex-direction: column;
  348. height: 180px !important;
  349. padding-bottom: 20px;
  350. align-items: center;
  351. justify-content: center;
  352. img {
  353. width: 150px;
  354. height: 150px;
  355. }
  356. span {
  357. color: #999;
  358. font-size: 14px;
  359. font-family: PingFangSC, PingFangSC-Medium;
  360. }
  361. }
  362. .wx-header-custom-detail {
  363. position: relative !important;
  364. }
  365. </style>