live-detail.tsx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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:0
  64. }
  65. },
  66. courseInfo() {
  67. const tempArr = [] as IProps[]
  68. const coursePlanList = this.live.planList || []
  69. coursePlanList.forEach((item: any) => {
  70. const startTime = item.startTime || new Date()
  71. const endTime = item.endTime || new Date()
  72. tempArr.push({
  73. courseTime: `${dayjs(startTime).format('YYYY-MM-DD')} ${dayjs(
  74. startTime
  75. ).format('HH:mm')}~${dayjs(endTime).format('HH:mm')}`,
  76. coursePlan: item.plan,
  77. roomUid: item.roomUid,
  78. liveState: item.liveState,
  79. id: item.courseId
  80. })
  81. })
  82. return tempArr || []
  83. },
  84. liveStatus() {
  85. const coursePlanList = this.live.planList || []
  86. const tempObj = {
  87. status: false,
  88. liveStatus: 0,
  89. roomUid: ''
  90. }
  91. coursePlanList.forEach((item: any) => {
  92. if (item.courseId === Number(this.courseId)) {
  93. tempObj.status = true
  94. tempObj.liveStatus = item.liveStatus
  95. tempObj.roomUid = item.roomUid
  96. }
  97. })
  98. return tempObj
  99. },
  100. studentList() {
  101. const live = this.live as any
  102. return live.studentList || []
  103. },
  104. courseOffStatus() {
  105. const live = this.live as any
  106. let status = false
  107. if (
  108. (live.status === 'APPLY' && live.studentList.length === 0) ||
  109. live.status === 'NOT_SALE'
  110. ) {
  111. status = true
  112. }
  113. return status
  114. }
  115. },
  116. async mounted() {
  117. try {
  118. const res = await request.get(
  119. '/api-teacher/courseGroup/queryLiveCourseInfo',
  120. {
  121. params: {
  122. groupId: this.groupId
  123. }
  124. }
  125. )
  126. this.live = res.data || {}
  127. if (state.platformType === 'TEACHER') {
  128. this.myself = !res.data.myself
  129. }
  130. this.shareUrl = `${location.origin}/teacher/#/shareLive?recomUserId=${state.user.data?.userId}&groupId=${this.groupId}`
  131. // console.log(this.live)
  132. } catch {
  133. //
  134. }
  135. },
  136. methods: {
  137. async onJoinRoom() {
  138. try {
  139. const res = await request.get(
  140. '/api-teacher/courseGroup/queryLiveCourseInfo',
  141. {
  142. params: {
  143. groupId: this.groupId
  144. }
  145. }
  146. )
  147. const result = res.data || {}
  148. const coursePlanList = result.planList || []
  149. let tempObj: any = {}
  150. coursePlanList.forEach((item: any) => {
  151. if (item.courseId === Number(this.courseId)) {
  152. tempObj = item
  153. }
  154. })
  155. if (tempObj && tempObj.liveState === 1) {
  156. postMessage({
  157. api: 'joinLiveRoom',
  158. content: {
  159. roomId: tempObj.roomUid,
  160. teacherId: this.live.teacherId
  161. }
  162. })
  163. } else if (tempObj && tempObj.liveState === 2) {
  164. setTimeout(() => {
  165. Toast('课程已结束')
  166. }, 100)
  167. } else {
  168. setTimeout(() => {
  169. Toast('课程尚未开始,请耐心等候')
  170. }, 100)
  171. }
  172. } catch {
  173. //
  174. }
  175. },
  176. async cancelCourseGroup() {
  177. try {
  178. await request.get('/api-teacher/courseGroup/cancelCourseGroup', {
  179. params: {
  180. groupId: this.groupId
  181. }
  182. })
  183. Toast('下架成功')
  184. setTimeout(() => {
  185. postMessage({ api: 'back', content: {} })
  186. }, 500)
  187. } catch {
  188. //
  189. }
  190. }
  191. },
  192. render() {
  193. return (
  194. <div class={[styles['live-detail'], 'mb12']}>
  195. <UserDetail userInfo={this.userInfo} />
  196. <SectionDetail border>
  197. <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
  198. </SectionDetail>
  199. {this.myself ? (
  200. <SectionDetail title="课程列表" icon="courseList" border={true}>
  201. <CoursePlanStep
  202. courseInfo={this.courseInfo}
  203. courseId={Number(this.courseId) || 0}
  204. />
  205. </SectionDetail>
  206. ) : (
  207. <SectionDetail
  208. title="课程列表"
  209. icon="courseList"
  210. titleShow={false}
  211. contentStyle={{ paddingTop: '0' }}
  212. >
  213. <Tabs color="var(--van-primary)" lineWidth={20} sticky>
  214. <Tab title="课程" titleClass="van-hairline--bottom">
  215. <CoursePlanStep
  216. courseInfo={this.courseInfo}
  217. courseId={Number(this.courseId) || 0}
  218. />
  219. </Tab>
  220. <Tab title="学员列表" titleClass="van-hairline--bottom">
  221. {this.studentList.map((item: any) => (
  222. <UserList
  223. class="mb12"
  224. users={{
  225. avatar: item.avatar,
  226. studentId: item.studentId,
  227. studentName: item.userName,
  228. createTime: item.createTime
  229. }}
  230. />
  231. ))}
  232. {this.studentList.length === 0 && (
  233. <ColResult
  234. tips="暂无购买学员"
  235. classImgSize="SMALL"
  236. btnStatus={false}
  237. />
  238. )}
  239. </Tab>
  240. </Tabs>
  241. </SectionDetail>
  242. )}
  243. {this.live.status !== 'OUT_SALE' && (
  244. <>
  245. {this.courseOffStatus && (
  246. <ColSticky position="bottom">
  247. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  248. <Button
  249. block
  250. round
  251. type="primary"
  252. onClick={this.cancelCourseGroup}
  253. >
  254. 下架
  255. </Button>
  256. </div>
  257. </ColSticky>
  258. )}
  259. {this.joinRoom == '1' && this.liveStatus.liveStatus !== 2 && (
  260. <ColSticky position="bottom">
  261. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  262. <Button block round type="primary" onClick={this.onJoinRoom}>
  263. 进入直播间
  264. </Button>
  265. </div>
  266. </ColSticky>
  267. )}
  268. {this.share == '1' && this.courseInfo.length > 0 && (
  269. <ColSticky position="bottom">
  270. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  271. <Button
  272. block
  273. round
  274. type="primary"
  275. onClick={() => {
  276. this.shareStatus = true
  277. }}
  278. >
  279. 分享
  280. </Button>
  281. </div>
  282. </ColSticky>
  283. )}
  284. </>
  285. )}
  286. <Popup
  287. v-model:show={this.shareStatus}
  288. style={{ background: 'transparent' }}
  289. >
  290. <ColShare
  291. teacherId={this.userInfo.id}
  292. shareUrl={this.shareUrl}
  293. shareType="live"
  294. >
  295. <LiveItem
  296. class={styles.shareCourse}
  297. liveInfo={{
  298. backgroundPic: this.userInfo.lessonCoverUrl,
  299. courseGroupId: this.userInfo.lessonId,
  300. courseGroupName: this.userInfo.lessonName,
  301. courseNum: this.userInfo.lessonNum,
  302. coursePrice: this.userInfo.lessonPrice,
  303. teacherName: this.userInfo.username,
  304. teacherId: this.userInfo.id,
  305. avatar: this.userInfo.avatar,
  306. studentCount: this.userInfo.buyNum,
  307. courseStartTime: this.userInfo.courseStartTime,
  308. existBuy: 0,
  309. subjectName: this.userInfo.subjectName
  310. }}
  311. />
  312. </ColShare>
  313. </Popup>
  314. </div>
  315. )
  316. }
  317. })