video-detail.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import CourseVideoItem from '@/business-components/course-video-item'
  2. import SectionDetail from '@/business-components/section-detail'
  3. import UserDetail from '@/business-components/user-detail'
  4. import { Sticky, Button, Dialog, Popup, Toast } from 'vant'
  5. import { postMessage } from '@/helpers/native-message'
  6. import { defineComponent } from 'vue'
  7. import styles from './video-detail.module.less'
  8. import request from '@/helpers/request'
  9. import ColHeader from '@/components/col-header'
  10. import { onSubmitZero, orderStatus } from '@/views/order-detail/orderStatus'
  11. import { tradeOrder } from '../trade/tradeOrder'
  12. import ColSticky from '@/components/col-sticky'
  13. import iconShare from '@/views/shop-mall/images/icon-share.svg'
  14. import ColShare from '@/components/col-share'
  15. import LiveItem from '@/views/live-class/live-item'
  16. import { setLogin, state } from '@/state'
  17. import { browser, getHttpOrigin } from '@/helpers/utils'
  18. import { usePageVisibility } from '@vant/use'
  19. import TheSticky from '@/components/the-sticky'
  20. import { useStatisticTracking } from '@/helpers/hooks'
  21. export default defineComponent({
  22. name: 'VideoDetail',
  23. data() {
  24. const query = this.$route.query
  25. return {
  26. pageVisibility: 'visible' as any,
  27. userInfo: {} as any,
  28. detailList: [],
  29. recomUserId: query.recomUserId, // 推荐人id
  30. params: {
  31. groupId: query.groupId
  32. },
  33. platform: query.p, // 属于哪个平台,//机构老师 tenant,平台老师 无
  34. shareStatus: false,
  35. shareUrl: ''
  36. }
  37. },
  38. computed: {
  39. platformStatus() {
  40. const userInfo = state.user.data as any
  41. // 是机构学生 并且 是机构老师分享
  42. const query = this.$route.query
  43. return userInfo.tenantId > 0 && query.p == 'tenant'
  44. }
  45. },
  46. async mounted() {
  47. this.pageVisibility = usePageVisibility()
  48. await this._init()
  49. // if (/(localhost|192)/g.test(location.origin)) {
  50. // this.shareUrl = `https://dev.colexiu.com/teacher#/shareVideo?recomUserId=${state.user.data?.userId}&groupId=${this.params.groupId}&userType=${state.platformType}&p=tenant`
  51. // } else {
  52. this.shareUrl = `${getHttpOrigin()}/teacher#/shareVideo?recomUserId=${state.user.data?.userId}&groupId=${this.params.groupId}&userType=${state.platformType}&p=tenant`
  53. // }
  54. /** 埋点 */
  55. useStatisticTracking({
  56. objectType: "VIDEO",
  57. objectId: this.params.groupId as any
  58. })
  59. },
  60. methods: {
  61. async _init() {
  62. try {
  63. const res = await request.get(
  64. '/api-student/videoLesson/selectVideoLesson',
  65. {
  66. params: {
  67. groupId: this.params.groupId
  68. }
  69. }
  70. )
  71. const result = res.data || {}
  72. const lessonGroup = result.lessonGroup || {}
  73. const userInfo = state.user.data as any
  74. const alreadyBuy =
  75. lessonGroup.payType === 'VIP'
  76. ? result.alreadyBuy || userInfo.userVip?.vipType !== 'NOT_VIP'
  77. ? true
  78. : false
  79. : result.alreadyBuy
  80. this.userInfo = {
  81. alreadyBuy: alreadyBuy,
  82. username:
  83. lessonGroup.username || `游客${lessonGroup.teacherId || ''}`,
  84. headUrl: lessonGroup.avatar,
  85. buyNum: lessonGroup.countStudent,
  86. id: lessonGroup.id,
  87. lessonNum: lessonGroup.lessonCount,
  88. lessonName: lessonGroup.lessonName,
  89. payType: lessonGroup.payType,
  90. type: 'video',
  91. subjectName: lessonGroup.lessonSubjectName,
  92. lessonDesc: lessonGroup.lessonDesc,
  93. lessonPrice: lessonGroup.lessonPrice,
  94. relationType: lessonGroup.relationType,
  95. teacherId: lessonGroup.teacherId,
  96. lessonCoverUrl: lessonGroup.lessonCoverUrl,
  97. auditVersion: lessonGroup.auditVersion,
  98. isDegree: result.degreeFlag ? true : false,
  99. isTeacher: result.teacherFlag ? true : false
  100. }
  101. this.detailList = result.detailList || []
  102. } catch {
  103. //
  104. }
  105. },
  106. onPlay(detail: any) {
  107. this.$router.push({
  108. path: '/videoClassDetail',
  109. query: {
  110. groupId: this.params.groupId,
  111. classId: detail.id
  112. }
  113. })
  114. },
  115. initVideo () {
  116. const userInfo = this.userInfo
  117. orderStatus.orderObject.orderType = 'VIDEO'
  118. orderStatus.orderObject.orderName = '视频课购买'
  119. orderStatus.orderObject.orderDesc = '视频课购买'
  120. orderStatus.orderObject.actualPrice = userInfo.lessonPrice
  121. orderStatus.orderObject.recomUserId = this.recomUserId
  122. orderStatus.orderObject.orderNo = ''
  123. orderStatus.orderObject.orderList = [
  124. {
  125. orderType: 'VIDEO',
  126. goodsName: '视频课购买',
  127. courseGroupId: userInfo.id,
  128. courseGroupName: userInfo.lessonName,
  129. coursePrice: userInfo.lessonPrice,
  130. price: userInfo.lessonPrice,
  131. teacherName: userInfo.username || `游客${userInfo.teacherId || ''}`,
  132. teacherId: userInfo.teacherId,
  133. avatar: userInfo.headUrl,
  134. relationType: this.userInfo.relationType,
  135. courseInfo: this.detailList,
  136. recomUserId: this.recomUserId
  137. }
  138. ]
  139. },
  140. async onBuy() {
  141. try {
  142. if (this.userInfo.payType === 'VIP') {
  143. if (browser().isApp) {
  144. postMessage({
  145. api: 'openWebView',
  146. content: {
  147. url: `${getHttpOrigin()}${location.pathname}#/memberCenter`,
  148. orientation: 1,
  149. isHideTitle: false
  150. }
  151. })
  152. } else {
  153. this.$router.push({
  154. path: '/memberCenter'
  155. })
  156. }
  157. return
  158. }
  159. // const userInfo = this.userInfo
  160. // 判断是否是0无订单
  161. // if (userInfo.lessonPrice <= 0) {
  162. // this.initVideo()
  163. // await onSubmitZero(() => {
  164. // Dialog.alert({
  165. // message: '领取成功',
  166. // confirmButtonText: '确定',
  167. // confirmButtonColor: '#2dc7aa'
  168. // }).then(() => {
  169. // this._init()
  170. // })
  171. // })
  172. // return
  173. // }
  174. const res = await request.post(
  175. '/api-student/userOrder/getPendingOrder',
  176. {
  177. data: {
  178. goodType: 'VIDEO',
  179. bizId: this.params.groupId
  180. }
  181. }
  182. )
  183. const result = res.data
  184. if (result) {
  185. Dialog.confirm({
  186. title: '提示',
  187. message: '您有一个未支付的订单,是否继续支付?',
  188. confirmButtonColor: '#269a93',
  189. cancelButtonText: '取消订单',
  190. confirmButtonText: '继续支付'
  191. })
  192. .then(async () => {
  193. tradeOrder(result, this.routerTo)
  194. })
  195. .catch(() => {
  196. Dialog.close()
  197. // 只用取消订单,不用做其它处理
  198. this.cancelPayment(result.orderNo)
  199. })
  200. } else {
  201. this.initVideo()
  202. this.routerTo()
  203. }
  204. } catch {}
  205. },
  206. routerTo() {
  207. this.$router.push({
  208. path: '/orderDetail',
  209. query: {
  210. orderType: 'VIDEO',
  211. courseGroupId: this.params.groupId
  212. }
  213. })
  214. },
  215. async cancelPayment(orderNo: string) {
  216. try {
  217. await request.post('/api-student/userOrder/orderCancel', {
  218. data: {
  219. orderNo
  220. }
  221. })
  222. } catch {}
  223. }
  224. },
  225. watch: {
  226. pageVisibility() {
  227. // 如果不是会员则不用刷新
  228. if (this.userInfo.payType !== 'VIP') {
  229. return
  230. }
  231. if(this.pageVisibility === 'visible') {
  232. request
  233. .get('/api-student/student/queryUserInfo', {
  234. initRequest: true // 初始化接口
  235. })
  236. .then((res: any) => {
  237. setLogin(res.data)
  238. this.userInfo.alreadyBuy = this.userInfo.alreadyBuy || res.data.userVip?.vipType !== 'NOT_VIP'
  239. ? true
  240. : false
  241. })
  242. }
  243. }
  244. },
  245. render() {
  246. return (
  247. <div class={[styles['video-detail']]}>
  248. <ColHeader
  249. v-slots={{
  250. right: () => (
  251. <img src={iconShare} onClick={() => (this.shareStatus = true)} />
  252. )
  253. }}
  254. />
  255. <UserDetail
  256. userInfo={this.userInfo}
  257. showBuy={false}
  258. onUserDetail={(item: any) => {
  259. if (browser().isApp && state.platformType === 'STUDENT') {
  260. this.$router.push({
  261. path: '/teacherHome',
  262. query: {
  263. teacherId: item.teacherId,
  264. tabs: 'video'
  265. }
  266. })
  267. }
  268. }}
  269. />
  270. <SectionDetail border={false}>
  271. <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
  272. </SectionDetail>
  273. <SectionDetail
  274. title="课程列表"
  275. icon="courseList"
  276. class="mb12"
  277. border={false}
  278. >
  279. {this.detailList.map((item: any) => {
  280. const musicAlbumInfos = item.musicAlbumInfos || []
  281. const temp = musicAlbumInfos.map((info: any) => {
  282. return {
  283. relationMusicAlbum: info.relationType,
  284. musicAlbumName: info.name,
  285. musicAlbumId: info.musicAlbumId,
  286. status: info.status, // 是否上架
  287. useRelationType: this.userInfo.relationType
  288. }
  289. })
  290. return (
  291. <CourseVideoItem
  292. musicAlbumInfos={temp}
  293. class={[styles.videoItem]}
  294. detail={{
  295. id: item.id,
  296. title: item.videoTitle,
  297. content: item.videoContent,
  298. imgUrl: item.coverUrl
  299. }}
  300. onPlay={this.onPlay}
  301. onMusicAlbumDetail={(item: any) => {
  302. if (!this.userInfo.alreadyBuy && !item.status) {
  303. Toast('数据正在更新,请稍后再试')
  304. return
  305. }
  306. if (item.relationMusicAlbum === 'MUSIC') {
  307. this.$router.push({
  308. path: '/music-detail',
  309. query: {
  310. id: item.musicAlbumId
  311. }
  312. })
  313. } else if (item.relationMusicAlbum === 'ALBUM') {
  314. this.$router.push({
  315. path: '/music-album-detail/' + item.musicAlbumId
  316. })
  317. }
  318. }}
  319. />
  320. )
  321. })}
  322. </SectionDetail>
  323. {this.userInfo.id && !this.userInfo.alreadyBuy && (
  324. // <Sticky offsetBottom={0} position="bottom">
  325. // <div class={['btnGroup', styles.btnMore]}>
  326. // <Button block round type="primary" onClick={this.onBuy}>
  327. // {this.userInfo.lessonPrice <= 0 ? '免费领取' : `立即购买`}
  328. // </Button>
  329. // </div>
  330. // </Sticky>
  331. <TheSticky position="bottom">
  332. <div class={['btnGroup', styles.btnMore]}>
  333. <Button
  334. block
  335. round
  336. type="primary"
  337. onClick={this.onBuy}
  338. disabled={this.platformStatus}
  339. >
  340. {this.userInfo.payType === 'VIP'
  341. ? '开通会员'
  342. : this.userInfo.lessonPrice <= 0
  343. ? '免费领取'
  344. : `立即购买`}
  345. </Button>
  346. </div>
  347. </TheSticky>
  348. )}
  349. <Popup
  350. v-model:show={this.shareStatus}
  351. style={{ background: 'transparent' }}
  352. >
  353. <ColShare
  354. teacherId={this.userInfo.id}
  355. shareUrl={this.shareUrl}
  356. shareType="video"
  357. >
  358. <LiveItem
  359. class={styles.shareCourse}
  360. coverClass={styles.coverClass}
  361. liveInfo={{
  362. backgroundPic: this.userInfo.lessonCoverUrl,
  363. courseGroupId: this.userInfo.lessonId,
  364. courseGroupName: this.userInfo.lessonName,
  365. courseNum: this.userInfo.lessonNum,
  366. coursePrice: this.userInfo.lessonPrice,
  367. teacherName: this.userInfo.username,
  368. payType: this.userInfo.payType,
  369. teacherId: this.userInfo.id,
  370. avatar: this.userInfo.headUrl,
  371. studentCount: this.userInfo.buyNum,
  372. existBuy: 0,
  373. subjectName: this.userInfo.lessonSubjectName
  374. }}
  375. />
  376. </ColShare>
  377. </Popup>
  378. </div>
  379. )
  380. }
  381. })