live-detail.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import CoursePlanStep from '@/business-components/course-plan-step'
  2. import SectionDetail from '@/business-components/section-detail'
  3. import UserDetail from '@/business-components/user-detail'
  4. import UserList from '@/business-components/user-list'
  5. import ColResult from '@/components/col-result'
  6. import ColShare from '@/components/col-share'
  7. import ColSticky from '@/components/col-sticky'
  8. import { postMessage } from '@/helpers/native-message'
  9. import request from '@/helpers/request'
  10. import { state } from '@/state'
  11. import LiveItem from '@/views/live-class/live-item'
  12. import dayjs from 'dayjs'
  13. import { Button, Popup, Sticky, Tab, Tabs, Toast } from 'vant'
  14. import { defineComponent } from 'vue'
  15. import styles from './live-detail.module.less'
  16. interface IProps {
  17. courseTime: string
  18. coursePlan: string
  19. videoPosterUrl?: string
  20. roomUid?: string
  21. liveState?: number
  22. id?: number | string
  23. }
  24. export default defineComponent({
  25. name: 'LiveDetail',
  26. data() {
  27. const query = this.$route.query
  28. return {
  29. share: query.share,
  30. joinRoom: query.joinRoom, // 原生传递过来的参数,判断是否进入直播间
  31. groupId: query.groupId,
  32. courseId: query.classId,
  33. live: {} as any,
  34. shareStatus: false,
  35. shareUrl: '',
  36. myself: false
  37. }
  38. },
  39. computed: {
  40. userInfo() {
  41. const live = this.live as any
  42. const planList = live.planList || []
  43. const startTime = planList[0]?.startTime || new Date()
  44. const endTime = planList[0]?.endTime || new Date()
  45. return {
  46. headUrl: live.avatar,
  47. avatar: live.avatar,
  48. username: live.userName,
  49. id: live.teacherId,
  50. startTime:
  51. `${dayjs(startTime).format('YYYY-MM-DD')} ${dayjs(startTime).format(
  52. 'HH:mm'
  53. )}~${dayjs(endTime).format('HH:mm')}` || '',
  54. lessonPrice: live.coursePrice,
  55. buyNum: live.studentCount || 0,
  56. lessonId: live.courseGroupId,
  57. lessonNum: live.courseNum || 0, // 课时数
  58. lessonDesc: live.courseIntroduce,
  59. lessonCoverUrl: live.backgroundPic || live.backgroundPicTemplate,
  60. lessonName: live.courseGroupName,
  61. subjectName: live.subjectName,
  62. courseStartTime: live.courseStartTime,
  63. auditVersion: live.auditVersion || 0,
  64. isDegree: live.degreeFlag ? true : false,
  65. isTeacher: live.teacherFlag ? true : false
  66. }
  67. },
  68. courseInfo() {
  69. const tempArr = [] as IProps[]
  70. const coursePlanList = this.live.planList || []
  71. coursePlanList.forEach((item: any) => {
  72. const startTime = item.startTime || new Date()
  73. const endTime = item.endTime || new Date()
  74. tempArr.push({
  75. courseTime: `${dayjs(startTime).format('YYYY-MM-DD')} ${dayjs(
  76. startTime
  77. ).format('HH:mm')}~${dayjs(endTime).format('HH:mm')}`,
  78. coursePlan: item.plan,
  79. roomUid: item.roomUid,
  80. liveState: item.liveState,
  81. id: item.courseId
  82. })
  83. })
  84. return tempArr || []
  85. },
  86. liveStatus() {
  87. const coursePlanList = this.live.planList || []
  88. const tempObj = {
  89. status: false,
  90. liveStatus: 0,
  91. roomUid: ''
  92. }
  93. coursePlanList.forEach((item: any) => {
  94. if (item.courseId === Number(this.courseId)) {
  95. tempObj.status = true
  96. tempObj.liveStatus = item.liveStatus
  97. tempObj.roomUid = item.roomUid
  98. }
  99. })
  100. return tempObj
  101. },
  102. studentList() {
  103. const live = this.live as any
  104. return live.studentList || []
  105. },
  106. courseOffStatus() {
  107. const live = this.live as any
  108. let status = false
  109. if (
  110. (live.status === 'APPLY' && live.studentList.length === 0) ||
  111. live.status === 'NOT_SALE'
  112. ) {
  113. status = true
  114. }
  115. return status
  116. }
  117. },
  118. async mounted() {
  119. try {
  120. const res = await request.get(
  121. '/api-teacher/courseGroup/queryLiveCourseInfo',
  122. {
  123. params: {
  124. groupId: this.groupId
  125. }
  126. }
  127. )
  128. this.live = res.data || {}
  129. if (state.platformType === 'TEACHER') {
  130. this.myself = !res.data.myself
  131. }
  132. this.shareUrl = `${location.origin}/teacher/#/shareLive?recomUserId=${state.user.data?.userId}&groupId=${this.groupId}&p=tenant`
  133. // console.log(this.live)
  134. } catch {
  135. //
  136. }
  137. },
  138. methods: {
  139. async onJoinRoom() {
  140. try {
  141. const res = await request.get(
  142. '/api-teacher/courseGroup/queryLiveCourseInfo',
  143. {
  144. params: {
  145. groupId: this.groupId
  146. }
  147. }
  148. )
  149. const result = res.data || {}
  150. const coursePlanList = result.planList || []
  151. let tempObj: any = {}
  152. coursePlanList.forEach((item: any) => {
  153. if (item.courseId === Number(this.courseId)) {
  154. tempObj = item
  155. }
  156. })
  157. if (tempObj && tempObj.liveState === 1) {
  158. postMessage({
  159. api: 'joinLiveRoom',
  160. content: {
  161. roomId: tempObj.roomUid,
  162. teacherId: this.live.teacherId
  163. }
  164. })
  165. } else if (tempObj && tempObj.liveState === 2) {
  166. setTimeout(() => {
  167. Toast('课程已结束')
  168. }, 100)
  169. } else {
  170. setTimeout(() => {
  171. Toast('课程尚未开始,请耐心等候')
  172. }, 100)
  173. }
  174. } catch {
  175. //
  176. }
  177. },
  178. async cancelCourseGroup() {
  179. try {
  180. await request.get('/api-teacher/courseGroup/cancelCourseGroup', {
  181. params: {
  182. groupId: this.groupId
  183. }
  184. })
  185. Toast('取消课程成功')
  186. setTimeout(() => {
  187. postMessage({ api: 'back', content: {} })
  188. }, 500)
  189. } catch {
  190. //
  191. }
  192. }
  193. },
  194. render() {
  195. return (
  196. <div class={[styles['live-detail'], 'mb12']}>
  197. <UserDetail userInfo={this.userInfo} />
  198. <SectionDetail border>
  199. <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
  200. </SectionDetail>
  201. {this.myself ? (
  202. <SectionDetail title="课程列表" icon="courseList" border={true}>
  203. <CoursePlanStep
  204. courseInfo={this.courseInfo}
  205. courseId={Number(this.courseId) || 0}
  206. />
  207. </SectionDetail>
  208. ) : (
  209. <SectionDetail
  210. title="课程列表"
  211. icon="courseList"
  212. titleShow={false}
  213. contentStyle={{ paddingTop: '0' }}
  214. >
  215. <Tabs color="var(--van-primary)" lineWidth={20} sticky>
  216. <Tab title="课程" titleClass="van-hairline--bottom">
  217. <CoursePlanStep
  218. courseInfo={this.courseInfo}
  219. courseId={Number(this.courseId) || 0}
  220. />
  221. </Tab>
  222. <Tab title="学员列表" titleClass="van-hairline--bottom">
  223. {this.studentList.map((item: any) => (
  224. <UserList
  225. class="mb12"
  226. users={{
  227. avatar: item.avatar,
  228. studentId: item.studentId,
  229. studentName: item.userName,
  230. createTime: item.createTime
  231. }}
  232. />
  233. ))}
  234. {this.studentList.length === 0 && (
  235. <ColResult
  236. tips="暂无购买学员"
  237. classImgSize="SMALL"
  238. btnStatus={false}
  239. />
  240. )}
  241. </Tab>
  242. </Tabs>
  243. </SectionDetail>
  244. )}
  245. {this.live.status !== 'OUT_SALE' && (
  246. <>
  247. {this.courseOffStatus && (
  248. <ColSticky position="bottom" background="white">
  249. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  250. <Button
  251. block
  252. round
  253. type="primary"
  254. onClick={this.cancelCourseGroup}
  255. >
  256. 取消课程
  257. </Button>
  258. </div>
  259. </ColSticky>
  260. )}
  261. {this.joinRoom == '1' && this.liveStatus.liveStatus !== 2 && (
  262. <ColSticky position="bottom" background="white">
  263. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  264. <Button block round type="primary" onClick={this.onJoinRoom}>
  265. 进入直播间
  266. </Button>
  267. </div>
  268. </ColSticky>
  269. )}
  270. {this.share == '1' && this.courseInfo.length > 0 && (
  271. <ColSticky position="bottom" background="white">
  272. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  273. <Button
  274. block
  275. round
  276. type="primary"
  277. onClick={() => {
  278. this.shareStatus = true
  279. }}
  280. >
  281. 分享
  282. </Button>
  283. </div>
  284. </ColSticky>
  285. )}
  286. </>
  287. )}
  288. <Popup
  289. v-model:show={this.shareStatus}
  290. style={{ background: 'transparent' }}
  291. >
  292. <ColShare
  293. teacherId={this.userInfo.id}
  294. shareUrl={this.shareUrl}
  295. shareType="live"
  296. >
  297. <LiveItem
  298. class={styles.shareCourse}
  299. liveInfo={{
  300. backgroundPic: this.userInfo.lessonCoverUrl,
  301. courseGroupId: this.userInfo.lessonId,
  302. courseGroupName: this.userInfo.lessonName,
  303. courseNum: this.userInfo.lessonNum,
  304. coursePrice: this.userInfo.lessonPrice,
  305. teacherName: this.userInfo.username,
  306. teacherId: this.userInfo.id,
  307. avatar: this.userInfo.avatar,
  308. studentCount: this.userInfo.buyNum,
  309. courseStartTime: this.userInfo.courseStartTime,
  310. existBuy: 0,
  311. subjectName: this.userInfo.subjectName
  312. }}
  313. />
  314. </ColShare>
  315. </Popup>
  316. </div>
  317. )
  318. }
  319. })