@x-edu/live-player 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,475 +1,501 @@
1
- /* eslint-disable camelcase */
2
- import React, { useState, useEffect } from 'react'
3
- import { Icon } from 'fish'
4
- import dayjs from 'dayjs'
5
- import classNames from 'classnames'
6
- // import Empty from '@/component/Empty'
7
- import {
8
- getOpenClassLive
9
- // getServerTime
10
- } from '@/service/live'
11
- import { getIMLiveInfo, getGuestIMLiveInfo } from '@/service/imBroadcasts'
12
- import Loading from '@/component/status/Loading'
13
- import {
14
- PUBLIC_LIVE_STATUS, PUBLIC_LIVE_MODE, SUB_TYPE
15
- } from '@/config/publicLive'
16
- import { getUrlQuery } from '@/util/url'
17
- import { getRecordLiveStatus } from '@/util/live'
18
- import { isEmpty } from '@/util/object'
19
- // import IMChatroom from '@/component/IMChatroom'
20
- import RecordVideo from './RecordVideo'
21
- import LiveVideo from './LiveVideo'
22
- import LineSwitch from './LineSwitch'
23
- import ReplayVideo from './ReplayVideo'
24
- import style from './index.module.less'
25
- import LiveOnlineCount from './LiveOnlineCount'
26
- import { LOGIN_STATUS } from '@/config/constant/user'
27
- import { USER_IDENTITY_NAME } from '@/config/live'
28
- // import NotLoginChatroom from './NotLoginChatroom'
29
- import netUrl from '@/util/netUrl'
30
- import { ShortUrlMap } from './const'
31
- import { setUC } from '@/util/auth/func'
32
- import config from '@/config/env'
33
-
34
- const TrackPageName = 'edu_Platform_publiclive_detail_page'
35
-
36
- export default function PublicLiveDetail({
37
- containerClassName,
38
- className,
39
- infoClassName,
40
- playerClassName,
41
- descriptionClassName,
42
- errorCover, // 当直播不存在或者错误时候的封面展示
43
- errorText,
44
- replay: propRelay,
45
- liveId: propLiveId,
46
- sdpAppId: propSdpAppId,
47
- uc,
48
- loginInfo = {},
49
- handleLogin,
50
- onOnlineCountChange = () => {},
51
- onStateChange = () => {},
52
- onReportProgress = () => {},
53
- onReportTeacherTrain = () => {},
54
- onSendSensors = () => {}
55
- }) {
56
- setUC(uc, loginInfo?.userInfo)
57
- if (propSdpAppId) {
58
- config.app.appid = propSdpAppId
59
- }
60
-
61
- const { replay, live_id } = getUrlQuery()
62
- const matchId = propLiveId || live_id
63
- const replayMode = propRelay || replay
64
- const liveId = ShortUrlMap[matchId] || matchId
65
-
66
- const [liveInfo, setLiveInfo] = useState()
67
- const [visitTime, setVisitTime] = useState()
68
- const [diffTime, setDiffTime] = useState()
69
- const [isReplayMode, setIsReplayMode] = useState(!!replayMode)
70
- const [isExist, setIsExist] = useState(true)
71
- const [lineChanging, setLineChanging] = useState(false) // 线路切换中标识
72
-
73
- const {
74
- userInfo,
75
- userRole,
76
- loginStatus
77
- } = loginInfo
78
- const isLiveToReplay = !replay
79
- const isStreamLive = liveInfo
80
- && liveInfo.type === PUBLIC_LIVE_MODE.LIVING
81
-
82
- const handleStatusChange = async (status) => {
83
- const newLiveInfo = {
84
- ...liveInfo,
85
- status
86
- }
87
- setLiveInfo(newLiveInfo)
88
- onStateChange(newLiveInfo)
89
- const isRecordLive = liveInfo.type === PUBLIC_LIVE_MODE.RECORDED
90
- if (!isRecordLive
91
- && status === PUBLIC_LIVE_STATUS.LIVEING
92
- && isEmpty(liveInfo.imInfo)
93
- ) {
94
- const {
95
- sub_type: subType,
96
- bid,
97
- room_id: roomId
98
- } = liveInfo
99
- let imLiveInfoResp = {}
100
- // 如果类型为外部推流, 则去请求新的直播详情接口
101
- if (subType === SUB_TYPE.OUTSIDE || subType === SUB_TYPE.REBROADCAST) {
102
- imLiveInfoResp = await getGuestIMLiveInfo(bid)
103
- .catch(() => ({}))
104
-
105
- // 默认使用lines[0] 作为直播源
106
- imLiveInfoResp = {
107
- ...imLiveInfoResp,
108
- param: {
109
- ...imLiveInfoResp.param,
110
- ...imLiveInfoResp.param?.lines?.[0]
111
- }
112
- }
113
- } else {
114
- imLiveInfoResp = await getIMLiveInfo(roomId)
115
- .catch(() => ({}))
116
- }
117
- setLiveInfo({
118
- ...liveInfo,
119
- status,
120
- imInfo: imLiveInfoResp
121
- })
122
- }
123
- }
124
-
125
- const handleSelectChange = (lineSource) => {
126
- setLineChanging(true)
127
- setTimeout(() => {
128
- setLiveInfo({
129
- ...liveInfo,
130
- imInfo: {
131
- ...liveInfo.imInfo,
132
- param: {
133
- ...liveInfo.imInfo.param,
134
- ...lineSource
135
- }
136
- }
137
- })
138
- setLineChanging(false)
139
- }, 0)
140
- }
141
-
142
- useEffect(() => {
143
- const init = async () => {
144
- const [data, error] = await getOpenClassLive(liveId)
145
- .then((v) => [v], (err) => [null, err])
146
- if (error) {
147
- const { response } = error
148
- if (response.status === 404 || response.status === 400) {
149
- setIsExist(false)
150
- }
151
- return
152
- }
153
-
154
- const isRecordLive = data.type === PUBLIC_LIVE_MODE.RECORDED
155
- const isNoStarted = data.status === PUBLIC_LIVE_STATUS.NOSTARTED
156
- const isCompleted = data.status === PUBLIC_LIVE_STATUS.COMPLETEED
157
- const isOffline = data.status === PUBLIC_LIVE_STATUS.OFFLINE
158
-
159
- // 录播未完成或未下架,直播未开始时需要服务器时间
160
- let serverTime
161
- if ((isRecordLive && (!isCompleted || !isOffline)) || (!isRecordLive && !isReplayMode && isNoStarted)) {
162
- // const response = await getServerTime()
163
- serverTime = data.serverTime
164
- setDiffTime(data.diffTime)
165
- setVisitTime(serverTime)
166
- }
167
- // 录播计算状态
168
- if (isRecordLive) {
169
- const status = getRecordLiveStatus(data.status, serverTime, data.begin_time, data.end_time)
170
- data.status = status
171
- }
172
- if (!isRecordLive) {
173
- const {
174
- sub_type: subType,
175
- bid,
176
- room_id: roomId
177
- } = data
178
- let imLiveInfoResp = {}
179
- // 如果类型为外部推流, 则去请求新的直播详情接口
180
- if (subType === SUB_TYPE.OUTSIDE || subType === SUB_TYPE.REBROADCAST) {
181
- // if (subType === SUB_TYPE.OUTSIDE) {
182
- imLiveInfoResp = await getGuestIMLiveInfo(bid)
183
- .catch(() => ({}))
184
- // 默认使用lines[0] 作为直播源
185
- imLiveInfoResp = {
186
- ...imLiveInfoResp,
187
- param: {
188
- ...imLiveInfoResp.param,
189
- ...imLiveInfoResp.param?.lines?.[0]
190
- }
191
- }
192
- } else if (data.status === PUBLIC_LIVE_STATUS.LIVEING) {
193
- imLiveInfoResp = await getIMLiveInfo(roomId)
194
- .catch(() => ({}))
195
- }
196
- data.imInfo = imLiveInfoResp
197
- }
198
- // 如果是转播或者是推流 直接播放(用于调试模式)
199
- const { preview } = getUrlQuery() // 后台点预览会加这个参数
200
- const generateInfo = preview ? Object.assign(data, {
201
- status: 1
202
- }) : data
203
- setLiveInfo(generateInfo)
204
- }
205
- init()
206
- }, [])
207
-
208
- useEffect(() => {
209
- if (userInfo) {
210
- onReportProgress()
211
- }
212
- }, [userInfo])
213
-
214
- useEffect(() => {
215
- if (loginStatus !== LOGIN_STATUS.WAIT && liveInfo) {
216
- onSendSensors({
217
- pageName: TrackPageName,
218
- eventName: 'edu_Platform_publiclive_detail_page',
219
- params: {
220
- publiclive_id: liveInfo.live_id,
221
- publiclive_name: liveInfo.live_name,
222
- // 1-直播, 2-录播
223
- publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播',
224
- identity: userRole
225
- ? USER_IDENTITY_NAME[userRole]
226
- : '游客'
227
- }
228
- })
229
- }
230
- }, [!!userRole, !!liveInfo, loginStatus])
231
-
232
- if (!isExist) {
233
- return (
234
- <div
235
- className={classNames(
236
- style['public-live-detail-wrapper'],
237
- style['live-empty'],
238
- containerClassName
239
- )}
240
- style={{
241
- backgroundImage: `url(${errorCover})`
242
- }}
243
- >
244
- <div className={style['empty-marker']} />
245
- <div className={style['empty-content']}>
246
- {/* eslint-disable-next-line max-len */}
247
- <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAALOSURBVHgB7VqLbeMwDGVugctt4BEygje4bFBv0G5y2SC5Rc4jpBNEneDaLtBXCVIA16asL50U8AMEA7ZF6pG0PqSJVqxYIYkNCQHAVl8a3Xa6/dTt1+Dxs25v5rrZbN7o3qHJtLoddDsjHmfXp6V7gvGMbo+JZHxQuj3QraEHsXeDqQ11E4JaaaNbD3kcjS5aAlrRDmEvmefmu+lgjbAd9N86GXv3ToysHUlCK3hA2MItJcIRPQVky4RmgFSPCiED693TYuScRX14osowMnV79eirE5bOimqG2JEEMKNX1YgOQjj2b0GupxLAzmqxkCJnPgMuLPeUC4+1TPyfFib3xOhSGCwjKcK6uYHfgFzP6EqfuMB7qxm9sxg52O9tjHOqkDZ2sAuT43S1KQIOjIBdosLq5DwGP6QIGB9BVESfpcipkfy4cITdpGZZZQly4KMpPDt63P2bIiFNDvxsHd5mwR4n0jt+lSFGDvzs2I3f+8H05Ui8UAJ0gqbTl7/Mo64COS75MwlFjtgEOZkkKXKeseQRKxhER3KemwVHbGIR5OzJHGqTix1LFDFiXJ2CyuQa5t5kLeOIPTP3WipERXINc++dQkDBAh2D0qUAuQu065y8pUpBCTnkbqlcZ84qLVVEDjnwSaWkTXD0saUEqeRQemxxQrgiQ0OVEUsO/FbqQqkAn2coyw75dQXJed5JT6DCzo6KEVY9QUo0Tw62TFXurYEybqdvUmEiRQLE5TDzvTVS1jNCFYTKO1gqQQvpVDOvc47cpZpe+LOx5p5EUeLRQ+oDtT8DzKe7j6hXRupnSHUkAYRz+ccci8JuCObC778YqcEgUkq1e/f+uFTbOCPFlGovkC7VDgbXIG1qzoEJvX9Yqrg+ImisrlAXhpDxUn6Z6M4IXj1kZsSiE3t1IP+Xoz+ofCyS/knMfPTX6xWvZI/yJgXx8i1+EluxYsUEn1PRdSb/XhDOAAAAAElFTkSuQmCC" alt="" />
248
- <p>{errorText || '内容已失效'}</p>
249
- </div>
250
-
251
- </div>
252
- )
253
- }
254
-
255
- if (!liveInfo) {
256
- return <Loading />
257
- }
258
-
259
- const isRecordLive = liveInfo.type === PUBLIC_LIVE_MODE.RECORDED
260
- const beginTime = dayjs(liveInfo.begin_time)
261
-
262
- const handlePlayReplay = (needReport) => {
263
- if (needReport) {
264
- onSendSensors({
265
- pageName: TrackPageName,
266
- eventName: 'edu_Platform_publiclive_detail_replay_click',
267
- params: {
268
- publiclive_id: liveInfo.live_id,
269
- publiclive_name: liveInfo.live_name,
270
- // 1-直播, 2-录播
271
- publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播'
272
- }
273
- })
274
- }
275
-
276
- setIsReplayMode(true)
277
- }
278
-
279
- const handleRequestFullScreen = () => {
280
- onSendSensors({
281
- pageName: TrackPageName,
282
- eventName: 'edu_Platform_publiclive_detail_fullscreen_click'
283
- })
284
- }
285
-
286
- const handleVideoPlay = (needReport) => {
287
- if (needReport) {
288
- onSendSensors({
289
- pageName: TrackPageName,
290
- eventName: 'edu_Platform_publiclive_detail_play_click',
291
- params: {
292
- publiclive_id: liveInfo.live_id,
293
- publiclive_name: liveInfo.live_name,
294
- // 1-直播, 2-录播
295
- publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播'
296
- }
297
- })
298
- }
299
- if (userInfo) {
300
- // 登录且播放后上报
301
- onReportTeacherTrain(userInfo?.user_id, liveId)
302
- }
303
- }
304
-
305
- return (
306
- <>
307
- <div
308
- className={classNames(
309
- style['public-live-detail-wrapper'],
310
- containerClassName
311
- )}
312
- >
313
- <div
314
- className={classNames(
315
- className, style['live-panel']
316
- )}
317
- >
318
- <div className={infoClassName}>
319
-
320
- <div className={style['live-title']}>
321
- <div className={style['live-name']}>
322
- {liveInfo.live_name}
323
- </div>
324
- {
325
- // eslint-disable-next-line no-nested-ternary
326
- liveInfo.status === PUBLIC_LIVE_STATUS.LIVEING
327
- ? (
328
- <LiveOnlineCount
329
- className={style['live-online-count']}
330
- resId={liveId}
331
- onOnlineCountChange={onOnlineCountChange}
332
- />
333
- )
334
- : (
335
- liveInfo.status === PUBLIC_LIVE_STATUS.COMPLETEED
336
- ? (<div className={style['live-end']}>已结束</div>)
337
- : (<></>)
338
- )
339
- }
340
- </div>
341
- <div className={style['live-info']}>
342
- {/*
343
- 暂时隐藏主播
344
- <div className={classNames(style['live-user'], {
345
- [style['empty-user']]: !liveInfo.lecture_user_id && !liveInfo.lecture_user_name
346
- })}
347
- >
348
- <Avatar className={style.avatar} src={getAvatarURL(liveInfo.lecture_user_id)} />
349
- <span title={liveInfo.lecture_user_name}>{liveInfo.lecture_user_name}</span>
350
- </div> */
351
- }
352
- <div className={style['live-time']}>
353
- <Icon
354
- className={style['icon-time']}
355
- type="clock-circle"
356
- />
357
- <span>
358
- {`${beginTime.format(beginTime.isSame(dayjs(), 'day') ? '[今天] HH:mm' : 'YYYY-MM-DD HH:mm')} 开始`}
359
- </span>
360
- </div>
361
- </div>
362
- </div>
363
- <div
364
- className={classNames(style['live-video-wrapper'], playerClassName)}
365
- >
366
- <div className={style['live-wrap']}>
367
- {
368
- // eslint-disable-next-line no-nested-ternary
369
- isReplayMode
370
- ? (
371
- <ReplayVideo
372
- handleLogin={handleLogin}
373
- liveInfo={liveInfo}
374
- autoplay={isLiveToReplay}
375
- onVideoPlay={() => {
376
- handleVideoPlay(false)
377
- }}
378
- onRequestFullScreen={handleRequestFullScreen}
379
- />
380
- )
381
- : isRecordLive
382
- ? (
383
- <RecordVideo
384
- isStreamLive={isStreamLive}
385
- userInfo={userInfo}
386
- liveInfo={liveInfo}
387
- visitTime={visitTime}
388
- diffTime={diffTime}
389
- onStatusChange={handleStatusChange}
390
- onPlayReplay={() => {
391
- handlePlayReplay(true)
392
- }}
393
- onVideoPlay={() => {
394
- handleVideoPlay(true)
395
- }}
396
- onRequestFullScreen={handleRequestFullScreen}
397
- />
398
- )
399
- : (
400
- <LiveVideo
401
- isStreamLive={isStreamLive}
402
- handleLogin={handleLogin}
403
- userInfo={userInfo}
404
- liveInfo={liveInfo}
405
- visitTime={visitTime}
406
- lineChanging={lineChanging}
407
- onStatusChange={handleStatusChange}
408
- onPlayReplay={() => {
409
- handlePlayReplay(true)
410
- }}
411
- onVideoPlay={() => {
412
- handleVideoPlay(true)
413
- }}
414
- onRequestFullScreen={handleRequestFullScreen}
415
- />
416
- )
417
- }
418
- {/* {
419
- liveInfo?.chat_type && (
420
- <div className={style['chatroom-wrap']}>
421
- <div className={style['chatroom-title']}>
422
- 讨论区
423
- </div>
424
- {
425
- userInfo ? (
426
- <>
427
- <div className={style['chatroom-top-hint']}>
428
- 系统提示:倡导建康的直播环境,若发布违法、违规、低俗等不良消息,我们会对违规内容及帐号进行封禁处理。
429
- </div>
430
- <IMChatroom
431
- roomId={liveInfo.chat_room_id}
432
- disableEditor={!liveInfo.chat_enabled}
433
- />
434
- </>
435
- ) : (
436
- <NotLoginChatroom
437
- handleLogin={handleLogin}
438
- />
439
- )
440
- }
441
- </div>
442
- )
443
- } */}
444
- </div>
445
- {
446
- !isReplayMode && !isRecordLive
447
- && liveInfo.sub_type !== SUB_TYPE.NET_DRAGON
448
- && liveInfo.status !== PUBLIC_LIVE_STATUS.COMPLETEED
449
- && (
450
- <LineSwitch
451
- className={style['live-line-switch']}
452
- liveInfo={liveInfo}
453
- onChange={handleSelectChange}
454
- />
455
- )
456
- }
457
- </div>
458
- </div>
459
- <div
460
- className={classNames(
461
- style['live-description-panel'],
462
- descriptionClassName
463
- )}
464
- >
465
- <div className={style['desc-title']}>开播介绍</div>
466
- <div className={style['desc-content']}>
467
- {!liveInfo.desc_pic_web_url ? '暂无介绍' : (
468
- <img className={style['desc-content-img']} src={netUrl(liveInfo.desc_pic_web_url)} alt="" />
469
- )}
470
- </div>
471
- </div>
472
- </div>
473
- </>
474
- )
475
- }
1
+ /* eslint-disable camelcase */
2
+ import React, { useState, useEffect } from 'react'
3
+ import { Icon } from 'fish'
4
+ import dayjs from 'dayjs'
5
+ import classNames from 'classnames'
6
+ // import Empty from '@/component/Empty'
7
+ import {
8
+ getOpenClassLive
9
+ // getServerTime
10
+ } from '@/service/live'
11
+ import { getIMLiveInfo, getGuestIMLiveInfo } from '@/service/imBroadcasts'
12
+ import Loading from '@/component/status/Loading'
13
+ import {
14
+ PUBLIC_LIVE_STATUS, PUBLIC_LIVE_MODE, PUBLIC_LIVE_PUSH_TOPIC, PUBLIC_LIVE_PUSH_EVENT, SUB_TYPE
15
+ } from '@/config/publicLive'
16
+ import { getUrlQuery } from '@/util/url'
17
+ import ImPush from '@/util/push'
18
+ import { getRecordLiveStatus } from '@/util/live'
19
+ import { isEmpty } from '@/util/object'
20
+ // import IMChatroom from '@/component/IMChatroom'
21
+ import RecordVideo from './RecordVideo'
22
+ import LiveVideo from './LiveVideo'
23
+ import LineSwitch from './LineSwitch'
24
+ import ReplayVideo from './ReplayVideo'
25
+ import style from './index.module.less'
26
+ import LiveOnlineCount from './LiveOnlineCount'
27
+ import { LOGIN_STATUS } from '@/config/constant/user'
28
+ import { USER_IDENTITY_NAME } from '@/config/live'
29
+ // import NotLoginChatroom from './NotLoginChatroom'
30
+ import netUrl from '@/util/netUrl'
31
+ import { ShortUrlMap } from './const'
32
+ import { setUC } from '@/util/auth/func'
33
+ import config from '@/config/env'
34
+
35
+ const TrackPageName = 'edu_Platform_publiclive_detail_page'
36
+
37
+ export default function PublicLiveDetail({
38
+ containerClassName,
39
+ className,
40
+ infoClassName,
41
+ playerClassName,
42
+ descriptionClassName,
43
+ errorCover, // 当直播不存在或者错误时候的封面展示
44
+ errorText,
45
+ replay: propRelay,
46
+ liveId: propLiveId,
47
+ sdpAppId: propSdpAppId,
48
+ uc,
49
+ loginInfo = {},
50
+ handleLogin,
51
+ onOnlineCountChange = () => {},
52
+ onStateChange = () => {},
53
+ onReportProgress = () => {},
54
+ onReportTeacherTrain = () => {},
55
+ onSendSensors = () => {}
56
+ }) {
57
+ setUC(uc, loginInfo?.userInfo)
58
+ if (propSdpAppId) {
59
+ config.app.appid = propSdpAppId
60
+ }
61
+
62
+ const { replay, live_id } = getUrlQuery()
63
+ const matchId = propLiveId || live_id
64
+ const replayMode = propRelay || replay
65
+ const liveId = ShortUrlMap[matchId] || matchId
66
+
67
+ const [liveInfo, setLiveInfo] = useState()
68
+ const [visitTime, setVisitTime] = useState()
69
+ const [diffTime, setDiffTime] = useState()
70
+ const [isReplayMode, setIsReplayMode] = useState(!!replayMode)
71
+ const [isExist, setIsExist] = useState(true)
72
+ const [lineChanging, setLineChanging] = useState(false) // 线路切换中标识
73
+
74
+ const {
75
+ userInfo,
76
+ userRole,
77
+ loginStatus
78
+ } = loginInfo
79
+ const isLiveToReplay = !replay
80
+ const isStreamLive = liveInfo
81
+ && liveInfo.type === PUBLIC_LIVE_MODE.LIVING
82
+ && (liveInfo.sub_type === SUB_TYPE.OUTSIDE || liveInfo.sub_type === SUB_TYPE.REBROADCAST)
83
+
84
+ const handleStatusChange = async (status) => {
85
+ const newLiveInfo = {
86
+ ...liveInfo,
87
+ status
88
+ }
89
+ setLiveInfo(newLiveInfo)
90
+ onStateChange(newLiveInfo)
91
+ const isRecordLive = liveInfo.type === PUBLIC_LIVE_MODE.RECORDED
92
+ if (!isRecordLive
93
+ && status === PUBLIC_LIVE_STATUS.LIVEING
94
+ && isEmpty(liveInfo.imInfo)
95
+ ) {
96
+ const {
97
+ sub_type: subType,
98
+ bid,
99
+ room_id: roomId
100
+ } = liveInfo
101
+ let imLiveInfoResp = {}
102
+ // 如果类型为外部推流, 则去请求新的直播详情接口
103
+ if (subType === SUB_TYPE.OUTSIDE || subType === SUB_TYPE.REBROADCAST) {
104
+ imLiveInfoResp = await getGuestIMLiveInfo(bid)
105
+ .catch(() => ({}))
106
+
107
+ // 默认使用lines[0] 作为直播源
108
+ imLiveInfoResp = {
109
+ ...imLiveInfoResp,
110
+ param: {
111
+ ...imLiveInfoResp.param,
112
+ ...imLiveInfoResp.param?.lines?.[0]
113
+ }
114
+ }
115
+ } else {
116
+ imLiveInfoResp = await getIMLiveInfo(roomId)
117
+ .catch(() => ({}))
118
+ }
119
+ setLiveInfo({
120
+ ...liveInfo,
121
+ status,
122
+ imInfo: imLiveInfoResp
123
+ })
124
+ }
125
+ }
126
+
127
+ const handleSelectChange = (lineSource) => {
128
+ setLineChanging(true)
129
+ setTimeout(() => {
130
+ setLiveInfo({
131
+ ...liveInfo,
132
+ imInfo: {
133
+ ...liveInfo.imInfo,
134
+ param: {
135
+ ...liveInfo.imInfo.param,
136
+ ...lineSource
137
+ }
138
+ }
139
+ })
140
+ setLineChanging(false)
141
+ }, 0)
142
+ }
143
+
144
+ useEffect(() => {
145
+ const init = async () => {
146
+ const [data, error] = await getOpenClassLive(liveId)
147
+ .then((v) => [v], (err) => [null, err])
148
+ if (error) {
149
+ const { response } = error
150
+ if (response.status === 404 || response.status === 400) {
151
+ setIsExist(false)
152
+ }
153
+ return
154
+ }
155
+
156
+ const isRecordLive = data.type === PUBLIC_LIVE_MODE.RECORDED
157
+ const isNoStarted = data.status === PUBLIC_LIVE_STATUS.NOSTARTED
158
+ const isCompleted = data.status === PUBLIC_LIVE_STATUS.COMPLETEED
159
+ const isOffline = data.status === PUBLIC_LIVE_STATUS.OFFLINE
160
+
161
+ // 录播未完成或未下架,直播未开始时需要服务器时间
162
+ let serverTime
163
+ if ((isRecordLive && (!isCompleted || !isOffline)) || (!isRecordLive && !isReplayMode && isNoStarted)) {
164
+ // const response = await getServerTime()
165
+ serverTime = data.serverTime
166
+ setDiffTime(data.diffTime)
167
+ setVisitTime(serverTime)
168
+ }
169
+ // 录播计算状态
170
+ if (isRecordLive) {
171
+ const status = getRecordLiveStatus(data.status, serverTime, data.begin_time, data.end_time)
172
+ data.status = status
173
+ }
174
+ if (!isRecordLive) {
175
+ const {
176
+ sub_type: subType,
177
+ bid,
178
+ room_id: roomId
179
+ } = data
180
+ let imLiveInfoResp = {}
181
+ // 如果类型为外部推流, 则去请求新的直播详情接口
182
+ if (subType === SUB_TYPE.OUTSIDE || subType === SUB_TYPE.REBROADCAST) {
183
+ // if (subType === SUB_TYPE.OUTSIDE) {
184
+ imLiveInfoResp = await getGuestIMLiveInfo(bid)
185
+ .catch(() => ({}))
186
+ // 默认使用lines[0] 作为直播源
187
+ imLiveInfoResp = {
188
+ ...imLiveInfoResp,
189
+ param: {
190
+ ...imLiveInfoResp.param,
191
+ ...imLiveInfoResp.param?.lines?.[0]
192
+ }
193
+ }
194
+ } else if (data.status === PUBLIC_LIVE_STATUS.LIVEING) {
195
+ imLiveInfoResp = await getIMLiveInfo(roomId)
196
+ .catch(() => ({}))
197
+ }
198
+ data.imInfo = imLiveInfoResp
199
+ }
200
+ // 推流直播不加载im push
201
+ if (data.type === PUBLIC_LIVE_MODE.LIVING && data.sub_type === SUB_TYPE.OUTSIDE) {
202
+ // nothing
203
+ } else {
204
+ await ImPush.init()
205
+ }
206
+ // 如果是转播或者是推流 直接播放(用于调试模式)
207
+ const { preview } = getUrlQuery() // 后台点预览会加这个参数
208
+ const generateInfo = preview ? Object.assign(data, {
209
+ status: 1
210
+ }) : data
211
+ setLiveInfo(generateInfo)
212
+ }
213
+ init()
214
+ }, [])
215
+
216
+ useEffect(() => {
217
+ if (!liveInfo || liveInfo.sub_type === SUB_TYPE.OUTSIDE) {
218
+ return
219
+ }
220
+ const handler = (data) => {
221
+ const { extraFields = {} } = data
222
+ console.log('public Live:', data)
223
+ if (extraFields.event === PUBLIC_LIVE_PUSH_EVENT.STATUS_CHANGE && extraFields.liveId === liveId) {
224
+ console.log(`public Live: receive push status ${parseInt(extraFields.status, 10)}`)
225
+ handleStatusChange(parseInt(extraFields.status, 10))
226
+ }
227
+ }
228
+ ImPush.addTopicListener(`${PUBLIC_LIVE_PUSH_TOPIC}_${liveId}`, handler)
229
+ return () => {
230
+ if (!liveInfo || liveInfo.sub_type === SUB_TYPE.OUTSIDE) {
231
+ return
232
+ }
233
+ ImPush.removeTopicListener(`${PUBLIC_LIVE_PUSH_TOPIC}_${liveId}`, handler)
234
+ }
235
+ }, [!!liveInfo])
236
+
237
+ useEffect(() => {
238
+ if (userInfo) {
239
+ onReportProgress()
240
+ }
241
+ }, [userInfo])
242
+
243
+ useEffect(() => {
244
+ if (loginStatus !== LOGIN_STATUS.WAIT && liveInfo) {
245
+ onSendSensors({
246
+ pageName: TrackPageName,
247
+ eventName: 'edu_Platform_publiclive_detail_page',
248
+ params: {
249
+ publiclive_id: liveInfo.live_id,
250
+ publiclive_name: liveInfo.live_name,
251
+ // 1-直播, 2-录播
252
+ publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播',
253
+ identity: userRole
254
+ ? USER_IDENTITY_NAME[userRole]
255
+ : '游客'
256
+ }
257
+ })
258
+ }
259
+ }, [!!userRole, !!liveInfo, loginStatus])
260
+
261
+ if (!isExist) {
262
+ return (
263
+ <div
264
+ className={classNames(
265
+ style['public-live-detail-wrapper'],
266
+ style['live-empty'],
267
+ containerClassName
268
+ )}
269
+ style={{
270
+ backgroundImage: `url(${errorCover})`
271
+ }}
272
+ >
273
+ <div className={style['empty-marker']} />
274
+ <div className={style['empty-content']}>
275
+ {/* eslint-disable-next-line max-len */}
276
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAALOSURBVHgB7VqLbeMwDGVugctt4BEygje4bFBv0G5y2SC5Rc4jpBNEneDaLtBXCVIA16asL50U8AMEA7ZF6pG0PqSJVqxYIYkNCQHAVl8a3Xa6/dTt1+Dxs25v5rrZbN7o3qHJtLoddDsjHmfXp6V7gvGMbo+JZHxQuj3QraEHsXeDqQ11E4JaaaNbD3kcjS5aAlrRDmEvmefmu+lgjbAd9N86GXv3ToysHUlCK3hA2MItJcIRPQVky4RmgFSPCiED693TYuScRX14osowMnV79eirE5bOimqG2JEEMKNX1YgOQjj2b0GupxLAzmqxkCJnPgMuLPeUC4+1TPyfFib3xOhSGCwjKcK6uYHfgFzP6EqfuMB7qxm9sxg52O9tjHOqkDZ2sAuT43S1KQIOjIBdosLq5DwGP6QIGB9BVESfpcipkfy4cITdpGZZZQly4KMpPDt63P2bIiFNDvxsHd5mwR4n0jt+lSFGDvzs2I3f+8H05Ui8UAJ0gqbTl7/Mo64COS75MwlFjtgEOZkkKXKeseQRKxhER3KemwVHbGIR5OzJHGqTix1LFDFiXJ2CyuQa5t5kLeOIPTP3WipERXINc++dQkDBAh2D0qUAuQu065y8pUpBCTnkbqlcZ84qLVVEDjnwSaWkTXD0saUEqeRQemxxQrgiQ0OVEUsO/FbqQqkAn2coyw75dQXJed5JT6DCzo6KEVY9QUo0Tw62TFXurYEybqdvUmEiRQLE5TDzvTVS1jNCFYTKO1gqQQvpVDOvc47cpZpe+LOx5p5EUeLRQ+oDtT8DzKe7j6hXRupnSHUkAYRz+ccci8JuCObC778YqcEgUkq1e/f+uFTbOCPFlGovkC7VDgbXIG1qzoEJvX9Yqrg+ImisrlAXhpDxUn6Z6M4IXj1kZsSiE3t1IP+Xoz+ofCyS/knMfPTX6xWvZI/yJgXx8i1+EluxYsUEn1PRdSb/XhDOAAAAAElFTkSuQmCC" alt="" />
277
+ <p>{errorText || '内容已失效'}</p>
278
+ </div>
279
+
280
+ </div>
281
+ )
282
+ }
283
+
284
+ if (!liveInfo) {
285
+ return <Loading />
286
+ }
287
+
288
+ const isRecordLive = liveInfo.type === PUBLIC_LIVE_MODE.RECORDED
289
+ const beginTime = dayjs(liveInfo.begin_time)
290
+
291
+ const handlePlayReplay = (needReport) => {
292
+ if (needReport) {
293
+ onSendSensors({
294
+ pageName: TrackPageName,
295
+ eventName: 'edu_Platform_publiclive_detail_replay_click',
296
+ params: {
297
+ publiclive_id: liveInfo.live_id,
298
+ publiclive_name: liveInfo.live_name,
299
+ // 1-直播, 2-录播
300
+ publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播'
301
+ }
302
+ })
303
+ }
304
+
305
+ setIsReplayMode(true)
306
+ }
307
+
308
+ const handleRequestFullScreen = () => {
309
+ onSendSensors({
310
+ pageName: TrackPageName,
311
+ eventName: 'edu_Platform_publiclive_detail_fullscreen_click'
312
+ })
313
+ }
314
+
315
+ const handleVideoPlay = (needReport) => {
316
+ if (needReport) {
317
+ onSendSensors({
318
+ pageName: TrackPageName,
319
+ eventName: 'edu_Platform_publiclive_detail_play_click',
320
+ params: {
321
+ publiclive_id: liveInfo.live_id,
322
+ publiclive_name: liveInfo.live_name,
323
+ // 1-直播, 2-录播
324
+ publiclive_type: liveInfo.type === 1 ? '实时直播' : '录播直播'
325
+ }
326
+ })
327
+ }
328
+ if (userInfo) {
329
+ // 登录且播放后上报
330
+ onReportTeacherTrain(userInfo?.user_id, liveId)
331
+ }
332
+ }
333
+
334
+ return (
335
+ <>
336
+ <div
337
+ className={classNames(
338
+ style['public-live-detail-wrapper'],
339
+ containerClassName
340
+ )}
341
+ >
342
+ <div
343
+ className={classNames(
344
+ className, style['live-panel']
345
+ )}
346
+ >
347
+ <div className={infoClassName}>
348
+
349
+ <div className={style['live-title']}>
350
+ <div className={style['live-name']}>
351
+ {liveInfo.live_name}
352
+ </div>
353
+ {
354
+ // eslint-disable-next-line no-nested-ternary
355
+ liveInfo.status === PUBLIC_LIVE_STATUS.LIVEING
356
+ ? (
357
+ <LiveOnlineCount
358
+ className={style['live-online-count']}
359
+ resId={liveId}
360
+ onOnlineCountChange={onOnlineCountChange}
361
+ />
362
+ )
363
+ : (
364
+ liveInfo.status === PUBLIC_LIVE_STATUS.COMPLETEED
365
+ ? (<div className={style['live-end']}>已结束</div>)
366
+ : (<></>)
367
+ )
368
+ }
369
+ </div>
370
+ <div className={style['live-info']}>
371
+ {/*
372
+ 暂时隐藏主播
373
+ <div className={classNames(style['live-user'], {
374
+ [style['empty-user']]: !liveInfo.lecture_user_id && !liveInfo.lecture_user_name
375
+ })}
376
+ >
377
+ <Avatar className={style.avatar} src={getAvatarURL(liveInfo.lecture_user_id)} />
378
+ <span title={liveInfo.lecture_user_name}>{liveInfo.lecture_user_name}</span>
379
+ </div> */
380
+ }
381
+ <div className={style['live-time']}>
382
+ <Icon
383
+ className={style['icon-time']}
384
+ type="clock-circle"
385
+ />
386
+ <span>
387
+ {`${beginTime.format(beginTime.isSame(dayjs(), 'day') ? '[今天] HH:mm' : 'YYYY-MM-DD HH:mm')} 开始`}
388
+ </span>
389
+ </div>
390
+ </div>
391
+ </div>
392
+ <div
393
+ className={classNames(style['live-video-wrapper'], playerClassName)}
394
+ >
395
+ <div className={style['live-wrap']}>
396
+ {
397
+ // eslint-disable-next-line no-nested-ternary
398
+ isReplayMode
399
+ ? (
400
+ <ReplayVideo
401
+ handleLogin={handleLogin}
402
+ liveInfo={liveInfo}
403
+ autoplay={isLiveToReplay}
404
+ onVideoPlay={() => {
405
+ handleVideoPlay(false)
406
+ }}
407
+ onRequestFullScreen={handleRequestFullScreen}
408
+ />
409
+ )
410
+ : isRecordLive
411
+ ? (
412
+ <RecordVideo
413
+ userInfo={userInfo}
414
+ liveInfo={liveInfo}
415
+ visitTime={visitTime}
416
+ diffTime={diffTime}
417
+ onStatusChange={handleStatusChange}
418
+ onPlayReplay={() => {
419
+ handlePlayReplay(true)
420
+ }}
421
+ onVideoPlay={() => {
422
+ handleVideoPlay(true)
423
+ }}
424
+ onRequestFullScreen={handleRequestFullScreen}
425
+ />
426
+ )
427
+ : (
428
+ <LiveVideo
429
+ handleLogin={handleLogin}
430
+ userInfo={userInfo}
431
+ liveInfo={liveInfo}
432
+ visitTime={visitTime}
433
+ lineChanging={lineChanging}
434
+ onStatusChange={handleStatusChange}
435
+ onPlayReplay={() => {
436
+ handlePlayReplay(true)
437
+ }}
438
+ onVideoPlay={() => {
439
+ handleVideoPlay(true)
440
+ }}
441
+ onRequestFullScreen={handleRequestFullScreen}
442
+ />
443
+ )
444
+ }
445
+ {/* {
446
+ liveInfo?.chat_type && (
447
+ <div className={style['chatroom-wrap']}>
448
+ <div className={style['chatroom-title']}>
449
+ 讨论区
450
+ </div>
451
+ {
452
+ userInfo ? (
453
+ <>
454
+ <div className={style['chatroom-top-hint']}>
455
+ 系统提示:倡导建康的直播环境,若发布违法、违规、低俗等不良消息,我们会对违规内容及帐号进行封禁处理。
456
+ </div>
457
+ <IMChatroom
458
+ roomId={liveInfo.chat_room_id}
459
+ disableEditor={!liveInfo.chat_enabled}
460
+ />
461
+ </>
462
+ ) : (
463
+ <NotLoginChatroom
464
+ handleLogin={handleLogin}
465
+ />
466
+ )
467
+ }
468
+ </div>
469
+ )
470
+ } */}
471
+ </div>
472
+ {
473
+ !isReplayMode && !isRecordLive && isStreamLive
474
+ && liveInfo.status !== PUBLIC_LIVE_STATUS.COMPLETEED
475
+ && (
476
+ <LineSwitch
477
+ className={style['live-line-switch']}
478
+ liveInfo={liveInfo}
479
+ onChange={handleSelectChange}
480
+ />
481
+ )
482
+ }
483
+ </div>
484
+ </div>
485
+ <div
486
+ className={classNames(
487
+ style['live-description-panel'],
488
+ descriptionClassName
489
+ )}
490
+ >
491
+ <div className={style['desc-title']}>开播介绍</div>
492
+ <div className={style['desc-content']}>
493
+ {!liveInfo.desc_pic_web_url ? '暂无介绍' : (
494
+ <img className={style['desc-content-img']} src={netUrl(liveInfo.desc_pic_web_url)} alt="" />
495
+ )}
496
+ </div>
497
+ </div>
498
+ </div>
499
+ </>
500
+ )
501
+ }