|
@@ -0,0 +1,395 @@
|
|
|
+import CoursePlanStep from '@/business-components/course-plan-step'
|
|
|
+import SectionDetail from '@/business-components/section-detail'
|
|
|
+import UserDetail from '@/business-components/user-detail'
|
|
|
+import request from '@/helpers/request'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { Icon, Sticky, Button, Dialog, Toast, Popup } from 'vant'
|
|
|
+import { defineComponent } from 'vue'
|
|
|
+import styles from './live-detail.module.less'
|
|
|
+import iconTips from '@common/images/icon_tips.png'
|
|
|
+import { onSubmitZero, orderStatus } from '@/views/order-detail/orderStatus'
|
|
|
+import ColHeader from '@/components/col-header'
|
|
|
+import { postMessage } from '@/helpers/native-message'
|
|
|
+import ColSticky from '@/components/col-sticky'
|
|
|
+import ColShare from '@/components/col-share'
|
|
|
+import LiveItem from '@/views/live-class/live-item'
|
|
|
+import iconShare from '@/views/shop-mall/images/icon-share.svg'
|
|
|
+import { state } from '@/state'
|
|
|
+import { browser } from '@/helpers/utils'
|
|
|
+import { tradeOrder } from '../trade/tradeOrder'
|
|
|
+import { courseType } from '@/constant';
|
|
|
+interface IProps {
|
|
|
+ courseTime: string
|
|
|
+ coursePlan: string
|
|
|
+ videoPosterUrl?: string
|
|
|
+ roomUid?: string
|
|
|
+ liveState?: number
|
|
|
+ id?: number | string
|
|
|
+}
|
|
|
+export default defineComponent({
|
|
|
+ name: 'LiveDetail',
|
|
|
+ data() {
|
|
|
+ const query = this.$route.query
|
|
|
+ return {
|
|
|
+ joinRoom: query.joinRoom, // 原生传递过来的参数,判断是否进入直播间
|
|
|
+ recomUserId: query.recomUserId, // 推荐人id
|
|
|
+ groupId: query.groupId,
|
|
|
+ courseId: query.classId,
|
|
|
+ platform: query.p, // 属于哪个平台,//机构老师 tenant,平台老师 无
|
|
|
+ live: {} as any,
|
|
|
+ shareStatus: false,
|
|
|
+ shareUrl: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ userInfo() {
|
|
|
+ const live = this.live as any
|
|
|
+ // console.log('live', live)
|
|
|
+ const planList = live.planList || []
|
|
|
+ const startTime = planList[0]?.startTime || new Date()
|
|
|
+ const endTime = planList[0]?.endTime || new Date()
|
|
|
+ const studentNum = live.maxStudentNum || 0 - live.studentCount || 0
|
|
|
+ return {
|
|
|
+ avatar: live.avatar,
|
|
|
+ headUrl: live.avatar,
|
|
|
+ username: live.userName || `游客${live.teacherId || ''}`,
|
|
|
+ id: live.teacherId,
|
|
|
+ startTime:
|
|
|
+ `${dayjs(startTime).format('YYYY-MM-DD')} ${dayjs(startTime).format(
|
|
|
+ 'HH:mm'
|
|
|
+ )}~${dayjs(endTime).format('HH:mm')}` || '',
|
|
|
+ buyNum: live.studentCount,
|
|
|
+ type: 'group',
|
|
|
+ lessonId: live.courseGroupId,
|
|
|
+ lessonPrice: live.coursePrice,
|
|
|
+ lessonNum: live.courseNum,
|
|
|
+ mixStudentNum: studentNum > 0 ? studentNum : 0,
|
|
|
+ lessonDesc: live.courseIntroduce,
|
|
|
+ lessonCoverUrl: live.backgroundPic || live.backgroundPicTemplate,
|
|
|
+ lessonName: live.courseGroupName,
|
|
|
+ subjectName: live.subjectName,
|
|
|
+ courseStartTime: live.courseStartTime,
|
|
|
+ auditVersion: live.auditVersion || 0,
|
|
|
+ isDegree: live.degreeFlag ? true : false,
|
|
|
+ isTeacher: live.teacherFlag ? true : false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ platformStatus() {
|
|
|
+ const userInfo = state.user.data as any
|
|
|
+ // 是机构学生 并且 是机构老师分享
|
|
|
+ const query = this.$route.query
|
|
|
+ return userInfo.tenantId > 0 && query.p == 'tenant'
|
|
|
+ },
|
|
|
+ courseInfo() {
|
|
|
+ const tempArr = [] as IProps[]
|
|
|
+ const coursePlanList = this.live.planList || []
|
|
|
+ coursePlanList.forEach((item: any) => {
|
|
|
+ const startTime = item.startTime || new Date()
|
|
|
+ const endTime = item.endTime || new Date()
|
|
|
+ tempArr.push({
|
|
|
+ courseTime: `${dayjs(startTime).format('YYYY-MM-DD')} ${dayjs(
|
|
|
+ startTime
|
|
|
+ ).format('HH:mm')}~${dayjs(endTime).format('HH:mm')}`,
|
|
|
+ coursePlan: item.plan,
|
|
|
+ roomUid: item.roomUid,
|
|
|
+ liveState: item.liveState,
|
|
|
+ id: item.courseId
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return tempArr || []
|
|
|
+ },
|
|
|
+ salesEndDate() {
|
|
|
+ const live = this.live as any
|
|
|
+ return dayjs(live.salesEndDate || new Date()).format('YYYY-MM-DD')
|
|
|
+ },
|
|
|
+ liveStatus() {
|
|
|
+ const coursePlanList = this.live.planList || []
|
|
|
+ const tempObj = {
|
|
|
+ status: false,
|
|
|
+ liveStatus: 0,
|
|
|
+ roomUid: ''
|
|
|
+ }
|
|
|
+ coursePlanList.forEach((item: any) => {
|
|
|
+ if (item.courseId === Number(this.courseId)) {
|
|
|
+ tempObj.status = true
|
|
|
+ tempObj.liveStatus = item.liveStatus
|
|
|
+ tempObj.roomUid = item.roomUid
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return tempObj
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async mounted() {
|
|
|
+ await this._init()
|
|
|
+ if (/(localhost|192)/g.test(location.origin)) {
|
|
|
+ this.shareUrl = `https://dev.colexiu.com/teacher/#/shareLive?recomUserId=${state.user.data?.userId}&groupId=${this.groupId}&userType=${state.platformType}&p=tenant`
|
|
|
+ } else {
|
|
|
+ this.shareUrl = `${location.origin}/teacher/#/shareLive?recomUserId=${state.user.data?.userId}&groupId=${this.groupId}&userType=${state.platformType}&p=tenant`
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async _init() {
|
|
|
+ try {
|
|
|
+ const res = await request.get(
|
|
|
+ '/api-student/courseGroup/queryLiveCourseInfo',
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ groupId: this.groupId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ this.live = res.data || {}
|
|
|
+ console.log(this.live, "list");
|
|
|
+ } catch {}
|
|
|
+ },
|
|
|
+ async onJoinRoom() {
|
|
|
+ try {
|
|
|
+ const res = await request.get(
|
|
|
+ '/api-student/courseGroup/queryLiveCourseInfo',
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ courseType: 'GROUP',
|
|
|
+ groupId: this.groupId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ const result = res.data || {}
|
|
|
+ const coursePlanList = result.planList || []
|
|
|
+ let tempObj: any = {}
|
|
|
+ coursePlanList.forEach((item: any) => {
|
|
|
+ if (item.courseId === Number(this.courseId)) {
|
|
|
+ tempObj = item
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (tempObj && tempObj.liveState === 1) {
|
|
|
+ postMessage({
|
|
|
+ api: 'joinLiveRoom',
|
|
|
+ content: {
|
|
|
+ roomId: tempObj.roomUid,
|
|
|
+ teacherId: this.live.teacherId
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else if (tempObj && tempObj.liveState === 2) {
|
|
|
+ setTimeout(() => {
|
|
|
+ Toast('课程已结束')
|
|
|
+ }, 100)
|
|
|
+ } else {
|
|
|
+ setTimeout(() => {
|
|
|
+ Toast('课程尚未开始,请耐心等候')
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
+ } catch {}
|
|
|
+ },
|
|
|
+ initLive () {
|
|
|
+ const live = this.live
|
|
|
+ orderStatus.orderObject.orderType = 'GROUP'
|
|
|
+ orderStatus.orderObject.orderName = '小组课购买'
|
|
|
+ orderStatus.orderObject.orderDesc = '小组课购买'
|
|
|
+ orderStatus.orderObject.actualPrice = live.coursePrice
|
|
|
+ orderStatus.orderObject.recomUserId = this.recomUserId
|
|
|
+ orderStatus.orderObject.orderNo = ''
|
|
|
+ orderStatus.orderObject.orderList = [
|
|
|
+ {
|
|
|
+ orderType: 'GROUP',
|
|
|
+ goodsName: '小组课购买',
|
|
|
+ courseGroupId: live.courseGroupId,
|
|
|
+ courseGroupName: live.courseGroupName,
|
|
|
+ coursePrice: live.coursePrice,
|
|
|
+ price: live.coursePrice,
|
|
|
+ teacherName: live.userName || `游客${live.teacherId || ''}`,
|
|
|
+ teacherId: live.teacherId,
|
|
|
+ avatar: live.avatar,
|
|
|
+ courseInfo: this.courseInfo,
|
|
|
+ recomUserId: this.recomUserId
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ async onBuy() {
|
|
|
+ try {
|
|
|
+ const live = this.live
|
|
|
+ // 判断是否是0无订单
|
|
|
+ if (live.coursePrice <= 0) {
|
|
|
+ this.initLive()
|
|
|
+ await onSubmitZero(() => {
|
|
|
+ Dialog.alert({
|
|
|
+ message: '领取成功',
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ confirmButtonColor: '#2dc7aa'
|
|
|
+ }).then(() => {
|
|
|
+ this._init()
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const res = await request.post(
|
|
|
+ '/api-student/userOrder/getPendingOrder',
|
|
|
+ {
|
|
|
+ data: {
|
|
|
+ goodType: 'GROUP',
|
|
|
+ bizId: this.groupId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ const result = res.data
|
|
|
+ if (result) {
|
|
|
+ Dialog.confirm({
|
|
|
+ title: '提示',
|
|
|
+ message: '您有一个未支付的订单,是否继续支付?',
|
|
|
+ confirmButtonColor: '#269a93',
|
|
|
+ cancelButtonText: '取消订单',
|
|
|
+ confirmButtonText: '继续支付'
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ tradeOrder(result, this.routerTo)
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ Dialog.close()
|
|
|
+ // 只用取消订单,不用做其它处理
|
|
|
+ this.cancelPayment(result.orderNo)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this.initLive()
|
|
|
+ this.routerTo()
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ },
|
|
|
+ routerTo() {
|
|
|
+ const live = this.live
|
|
|
+ this.$router.push({
|
|
|
+ path: '/orderDetail',
|
|
|
+ query: {
|
|
|
+ orderType: 'GROUP',
|
|
|
+ courseGroupId: live.courseGroupId
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async cancelPayment(orderNo: string) {
|
|
|
+ try {
|
|
|
+ await request.post('/api-student/userOrder/orderCancel', {
|
|
|
+ data: {
|
|
|
+ orderNo
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // this.routerTo()
|
|
|
+ } catch {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render() {
|
|
|
+ return (
|
|
|
+ <div class={[styles['live-detail'], 'mb12']}>
|
|
|
+ <ColHeader
|
|
|
+ v-slots={{
|
|
|
+ right: () => (
|
|
|
+ <img src={iconShare} onClick={() => (this.shareStatus = true)} />
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <UserDetail
|
|
|
+ userInfo={this.userInfo}
|
|
|
+ showBuy={true}
|
|
|
+ onUserDetail={(item: any) => {
|
|
|
+ if (state.platformType === 'STUDENT' && browser().isApp) {
|
|
|
+ this.$router.push({
|
|
|
+ path: '/teacherHome',
|
|
|
+ query: {
|
|
|
+ teacherId: item.id,
|
|
|
+ tabs: 'live'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <SectionDetail border>
|
|
|
+ <p class={styles.introduction}>{this.userInfo.lessonDesc}</p>
|
|
|
+ </SectionDetail>
|
|
|
+
|
|
|
+ <SectionDetail
|
|
|
+ title="课程列表"
|
|
|
+ icon="courseList"
|
|
|
+ border
|
|
|
+ contentStyle={{ paddingTop: '0' }}
|
|
|
+ >
|
|
|
+ {this.courseInfo.length > 0 && (
|
|
|
+ <CoursePlanStep
|
|
|
+ courseInfo={this.courseInfo}
|
|
|
+ courseId={Number(this.courseId) || 0}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </SectionDetail>
|
|
|
+
|
|
|
+ {/* <div class={styles.tips}>
|
|
|
+ <h3>
|
|
|
+ <Icon name={iconTips} size={15} />
|
|
|
+ 温馨提示
|
|
|
+ </h3>
|
|
|
+ <p>
|
|
|
+ 1、该小组课程销售截止后,报名人数若少于
|
|
|
+ {this.live.mixStudentNum || 0}
|
|
|
+ 人将取消开课,已购买学员付费金额将自动返还,请您放心购买;
|
|
|
+ <br />
|
|
|
+ 2、小组课教学计划中的上课时间为老师预计时间,实际上课时间以老师开启直播时间为准;
|
|
|
+ <br />
|
|
|
+ 3、若您错过老师直播,可通过视频回放观看完整课程。
|
|
|
+ </p>
|
|
|
+ </div> */}
|
|
|
+ {this.courseInfo.length > 0 && (this.live.existBuy !== 1 || this.live.existBuy !== 2) && (
|
|
|
+ <ColSticky position="bottom" background="white">
|
|
|
+ <div class={['btnGroup', styles.btnMore]}>
|
|
|
+ <Button
|
|
|
+ block
|
|
|
+ round
|
|
|
+ type="primary"
|
|
|
+ onClick={this.onBuy}
|
|
|
+ disabled={this.platformStatus}
|
|
|
+ >
|
|
|
+ {this.live.coursePrice <= 0 ? '免费领取' : `立即购买`}
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </ColSticky>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {this.joinRoom == '1' && this.liveStatus.liveStatus !== 2 && (
|
|
|
+ <ColSticky position="bottom" background="white">
|
|
|
+ <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
|
|
|
+ <Button block round type="primary" onClick={this.onJoinRoom}>
|
|
|
+ 进入直播间
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </ColSticky>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <Popup
|
|
|
+ v-model:show={this.shareStatus}
|
|
|
+ style={{ background: 'transparent' }}
|
|
|
+ >
|
|
|
+ <ColShare
|
|
|
+ teacherId={this.userInfo.id}
|
|
|
+ shareUrl={this.shareUrl}
|
|
|
+ shareType="live"
|
|
|
+ >
|
|
|
+ <LiveItem
|
|
|
+ class={styles.shareCourse}
|
|
|
+ liveInfo={{
|
|
|
+ backgroundPic: this.userInfo.lessonCoverUrl,
|
|
|
+ courseGroupId: this.userInfo.lessonId,
|
|
|
+ courseGroupName: this.userInfo.lessonName,
|
|
|
+ courseNum: this.userInfo.lessonNum,
|
|
|
+ coursePrice: this.userInfo.lessonPrice,
|
|
|
+ teacherName: this.userInfo.username,
|
|
|
+ teacherId: this.userInfo.id,
|
|
|
+ avatar: this.userInfo.avatar,
|
|
|
+ studentCount: this.userInfo.buyNum,
|
|
|
+ courseStartTime: this.userInfo.courseStartTime,
|
|
|
+ existBuy: 0,
|
|
|
+ subjectName: this.userInfo.subjectName
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColShare>
|
|
|
+ </Popup>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+})
|