@x-edu/live-player 0.0.9 → 0.0.11
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.
- package/README.md +41 -1
- package/dist/XEduLivePlayer.common.js +50429 -37751
- package/dist/XEduLivePlayerPre.common.js +50399 -37721
- package/package.json +1 -1
- package/src/App.jsx +3 -1
- package/src/component/Avatar/index.jsx +1 -3
- package/src/component/Icon/index.jsx +16 -0
- package/src/component/Icon/index.module.less +3 -0
- package/src/component/Pagination/LocalPagination.jsx +27 -0
- package/src/component/Pagination/RemotePagination.jsx +32 -0
- package/src/component/Pagination/index.jsx +31 -0
- package/src/component/Pagination/index.module.less +110 -0
- package/src/config/request/live-activity.js +1 -1
- package/src/demo/Detail.jsx +11 -0
- package/src/demo/List.jsx +62 -0
- package/src/demo/index.jsx +17 -0
- package/src/detail/LiveStatus/index.jsx +2 -2
- package/src/detail/LiveVideo/index.jsx +2 -0
- package/src/detail/RecordVideo/index.jsx +2 -0
- package/src/detail/index.jsx +5 -31
- package/src/index.js +2 -7
- package/src/list/Empty/img/empty.png +0 -0
- package/src/list/Empty/index.jsx +20 -0
- package/src/list/Empty/index.module.less +23 -0
- package/src/list/ListItem/Action/index.jsx +98 -0
- package/src/list/ListItem/Action/index.module.less +22 -0
- package/src/list/ListItem/img/live.png +0 -0
- package/src/list/ListItem/img/play.svg +16 -0
- package/src/list/ListItem/index.jsx +95 -0
- package/src/list/ListItem/index.module.less +123 -0
- package/src/list/index.jsx +150 -0
- package/src/list/index.module.less +36 -0
- package/src/service/live.js +57 -0
package/package.json
CHANGED
package/src/App.jsx
CHANGED
|
@@ -8,6 +8,7 @@ import { parseAdapter } from '@/util/date'
|
|
|
8
8
|
|
|
9
9
|
import PublicLiveDetail from './detail'
|
|
10
10
|
import { getLiveOnlineCount } from './lib/getLiveOnlineCount'
|
|
11
|
+
import PublicLiveList from './list'
|
|
11
12
|
|
|
12
13
|
Icon.url = '/fish/icon/umd-4.1.2.js'
|
|
13
14
|
|
|
@@ -18,5 +19,6 @@ dayjs.locale('zh-cn')
|
|
|
18
19
|
|
|
19
20
|
export default {
|
|
20
21
|
PublicLiveDetail,
|
|
21
|
-
getLiveOnlineCount
|
|
22
|
+
getLiveOnlineCount,
|
|
23
|
+
PublicLiveList
|
|
22
24
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import classNames from 'classnames'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
const defaultAvatar = importImg('@/asset/img/def-avatar.jpg')
|
|
3
|
+
import defaultAvatar from '@/asset/img/def-avatar.jpg'
|
|
6
4
|
|
|
7
5
|
function Avatar({
|
|
8
6
|
onError = () => {},
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import style from './index.module.less'
|
|
4
|
+
|
|
5
|
+
export default function Icon({
|
|
6
|
+
className,
|
|
7
|
+
type
|
|
8
|
+
}) {
|
|
9
|
+
return (
|
|
10
|
+
<svg
|
|
11
|
+
className={classNames(style.icon, className)}
|
|
12
|
+
>
|
|
13
|
+
<use xlinkHref={`#${type}`} />
|
|
14
|
+
</svg>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import Pagination from './index'
|
|
3
|
+
|
|
4
|
+
export default function LocalPagination({
|
|
5
|
+
data,
|
|
6
|
+
pageSize,
|
|
7
|
+
defaultPage = 1,
|
|
8
|
+
renderData,
|
|
9
|
+
...restProps
|
|
10
|
+
}) {
|
|
11
|
+
const [currentPage, setCurrentPage] = useState(defaultPage)
|
|
12
|
+
const total = data.length
|
|
13
|
+
const pageData = data.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{pageData.map((dataItem, index) => renderData(dataItem, index))}
|
|
18
|
+
<Pagination
|
|
19
|
+
total={total}
|
|
20
|
+
current={currentPage}
|
|
21
|
+
pageSize={pageSize}
|
|
22
|
+
onChange={setCurrentPage}
|
|
23
|
+
{...restProps}
|
|
24
|
+
/>
|
|
25
|
+
</>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import Pagination from './index'
|
|
3
|
+
|
|
4
|
+
export default function RemotePagination({
|
|
5
|
+
total = 0,
|
|
6
|
+
data,
|
|
7
|
+
pageSize,
|
|
8
|
+
defaultPage = 1,
|
|
9
|
+
renderData,
|
|
10
|
+
onChange = () => {},
|
|
11
|
+
...restProps
|
|
12
|
+
}) {
|
|
13
|
+
const [currentPage, setCurrentPage] = useState(defaultPage)
|
|
14
|
+
|
|
15
|
+
const handlePageChange = (options) => {
|
|
16
|
+
setCurrentPage(options)
|
|
17
|
+
onChange(options)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{data.map((dataItem, index) => renderData(dataItem, index))}
|
|
23
|
+
<Pagination
|
|
24
|
+
total={total || data.length || 0}
|
|
25
|
+
current={currentPage}
|
|
26
|
+
pageSize={pageSize}
|
|
27
|
+
onChange={handlePageChange}
|
|
28
|
+
{...restProps}
|
|
29
|
+
/>
|
|
30
|
+
</>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { Pagination as FishPagination } from 'fish'
|
|
4
|
+
|
|
5
|
+
import style from './index.module.less'
|
|
6
|
+
|
|
7
|
+
export default function Pagination(props) {
|
|
8
|
+
const { className, current, total, pageSize, onChange = () => { }, showSizeChanger = false } = props
|
|
9
|
+
const pageCount = Math.ceil(total / pageSize)
|
|
10
|
+
|
|
11
|
+
if (pageCount > 1) {
|
|
12
|
+
return (
|
|
13
|
+
<div className={classNames(style.pagination, className, 'custom-pagination')}>
|
|
14
|
+
<span className={style['pagination-text']}>
|
|
15
|
+
{`当前第 ${current} 页/共 ${pageCount} 页,共有 ${total} 条记录`}
|
|
16
|
+
</span>
|
|
17
|
+
<FishPagination
|
|
18
|
+
total={total}
|
|
19
|
+
current={current}
|
|
20
|
+
pageSize={pageSize}
|
|
21
|
+
onChange={onChange}
|
|
22
|
+
showSizeChanger={showSizeChanger}
|
|
23
|
+
showQuickJumper={{
|
|
24
|
+
goButton: false
|
|
25
|
+
}}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
@primary-color: #1e62ec;
|
|
2
|
+
|
|
3
|
+
.pagination {
|
|
4
|
+
padding-bottom: 24px;
|
|
5
|
+
margin-top: 64px;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
align-items: center;
|
|
9
|
+
width: 100%;
|
|
10
|
+
|
|
11
|
+
.pagination-text {
|
|
12
|
+
color: #333;
|
|
13
|
+
margin-right: 16px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:global(.fish-pagination-prev), :global(.fish-pagination-next) {
|
|
17
|
+
// display: none;
|
|
18
|
+
button {
|
|
19
|
+
border: 0px;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:global(.fish-pagination-item) {
|
|
24
|
+
width: 32px;
|
|
25
|
+
height: 32px;
|
|
26
|
+
line-height: 32px;
|
|
27
|
+
background: #F5F7FA;
|
|
28
|
+
// border: 1px solid @primary-color;
|
|
29
|
+
border: 0px;
|
|
30
|
+
border-radius: 2px;
|
|
31
|
+
font-size: 14px;
|
|
32
|
+
font-weight: 400;
|
|
33
|
+
color: @primary-color;
|
|
34
|
+
margin-right: 10px;
|
|
35
|
+
|
|
36
|
+
a {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
padding: 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:global(.fish-pagination-item:hover) {
|
|
45
|
+
background: #F5F7FA;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:global(.fish-pagination-item-active:hover) {
|
|
49
|
+
background: @primary-color;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:global(.fish-pagination-item-link) {
|
|
53
|
+
background: #F5F7FA;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:global(.fish-pagination-item-link:hover) {
|
|
57
|
+
background: #F5F7FA;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:global(.fish-pagination-item-active) {
|
|
61
|
+
border-color: @primary-color;
|
|
62
|
+
background: @primary-color;
|
|
63
|
+
a {
|
|
64
|
+
color: #fff;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:global(.fish-pagination-options), :global(.fish-pagination-options-quick-jumper) {
|
|
69
|
+
margin-left: 8px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
:global(.fish-pagination-options-quick-jumper) {
|
|
73
|
+
:global(input) {
|
|
74
|
+
// border: 0;
|
|
75
|
+
background: transparent;
|
|
76
|
+
border-radius: 0;
|
|
77
|
+
outline: 0;
|
|
78
|
+
// border-bottom: 1px solid @primary-color;
|
|
79
|
+
height: 24px;
|
|
80
|
+
padding: 1px 7px;
|
|
81
|
+
width: 44px;
|
|
82
|
+
text-align: center;
|
|
83
|
+
&:focus {
|
|
84
|
+
outline: none;
|
|
85
|
+
box-shadow: none;
|
|
86
|
+
border-color: @primary-color;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&:hover {
|
|
90
|
+
border-color: @primary-color;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
:global(.fish-pagination-options-quick-jumper-btn) {
|
|
95
|
+
min-width: 40px;
|
|
96
|
+
line-height: 32px;
|
|
97
|
+
height: 32px;
|
|
98
|
+
margin-left: 12px;
|
|
99
|
+
background: transparent;
|
|
100
|
+
border: 0;
|
|
101
|
+
font-weight: 700;
|
|
102
|
+
color: @primary-color;
|
|
103
|
+
&:hover {
|
|
104
|
+
border-color: @primary-color;
|
|
105
|
+
background: @primary-color;
|
|
106
|
+
color: #fff;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import { UC } from '@sdp.nd/nd-uc-sdk'
|
|
3
|
+
import Live from '../App'
|
|
4
|
+
|
|
5
|
+
const uc = new UC({
|
|
6
|
+
env: 'ncet-xedu',
|
|
7
|
+
sdpAppId: 'e5649925-441d-4a53-b525-51a2f1c4e0a8',
|
|
8
|
+
origins: {
|
|
9
|
+
UC: 'https://uc-gateway.ykt.eduyun.cn',
|
|
10
|
+
SSO: 'https://sso.basic.smartedu.cn'
|
|
11
|
+
},
|
|
12
|
+
isGlobalSDKCacheEnabled: true
|
|
13
|
+
})
|
|
14
|
+
// const uc = new UC({
|
|
15
|
+
// env: 'preproduction',
|
|
16
|
+
// sdpAppId: '331593d3-af38-456e-bdb8-5263525608f4',
|
|
17
|
+
// origins: {
|
|
18
|
+
// UC: 'https://uc-gateway.beta.101.com',
|
|
19
|
+
// SSO: 'https://ysc-sso.ykt.eduyun.cn'
|
|
20
|
+
// },
|
|
21
|
+
// isGlobalSDKCacheEnabled: true
|
|
22
|
+
// })
|
|
23
|
+
|
|
24
|
+
export default function List() {
|
|
25
|
+
const [ucInstance, setUcInstance] = useState(uc)
|
|
26
|
+
const [userInfo, setUserInfo] = useState(null)
|
|
27
|
+
|
|
28
|
+
const handleSubscribe = (data) => {
|
|
29
|
+
console.log(data)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
async function init() {
|
|
34
|
+
try {
|
|
35
|
+
await ucInstance.login({
|
|
36
|
+
loginName: '18695708674',
|
|
37
|
+
password: 'gyh123456'
|
|
38
|
+
})
|
|
39
|
+
const account = ucInstance.getCurrentAccount()
|
|
40
|
+
const info = await account.getAccountInfo()
|
|
41
|
+
setUserInfo(info)
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.log(error)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
init()
|
|
47
|
+
}, [])
|
|
48
|
+
|
|
49
|
+
if (!userInfo) {
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Live.PublicLiveList
|
|
55
|
+
uc={ucInstance}
|
|
56
|
+
loginInfo={{
|
|
57
|
+
userInfo
|
|
58
|
+
}}
|
|
59
|
+
onSubscribe={handleSubscribe}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Tabs } from 'fish'
|
|
3
|
+
import Detail from './Detail'
|
|
4
|
+
import List from './List'
|
|
5
|
+
|
|
6
|
+
export default function Demo() {
|
|
7
|
+
return (
|
|
8
|
+
<Tabs>
|
|
9
|
+
<Tabs.TabPane tab="详情" key="detail">
|
|
10
|
+
<Detail />
|
|
11
|
+
</Tabs.TabPane>
|
|
12
|
+
<Tabs.TabPane tab="列表" key="list">
|
|
13
|
+
<List />
|
|
14
|
+
</Tabs.TabPane>
|
|
15
|
+
</Tabs>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import dayjs from 'dayjs'
|
|
3
3
|
import { Icon, Spin } from 'fish'
|
|
4
|
-
import { PROVIDE_RECORD, PUBLIC_LIVE_STATUS, VIEW_REPLAY, PUBLIC_LIVE_MODE
|
|
4
|
+
import { PROVIDE_RECORD, PUBLIC_LIVE_STATUS, VIEW_REPLAY, PUBLIC_LIVE_MODE } from '@/config/publicLive'
|
|
5
5
|
import LiveCountDown from '../LiveCountDown'
|
|
6
6
|
import style from './index.module.less'
|
|
7
7
|
import AnchorOnTheWay from './AnchorOnTheWay'
|
|
8
8
|
|
|
9
9
|
function LiveStatus({
|
|
10
|
+
isStreamLive,
|
|
10
11
|
handleLogin,
|
|
11
12
|
userInfo,
|
|
12
13
|
liveInfo,
|
|
@@ -26,7 +27,6 @@ function LiveStatus({
|
|
|
26
27
|
const isPaused = liveInfo.status === PUBLIC_LIVE_STATUS.PASUED
|
|
27
28
|
const isOffline = liveInfo.status === PUBLIC_LIVE_STATUS.OFFLINE
|
|
28
29
|
const isRecordLive = liveInfo.type === PUBLIC_LIVE_MODE.RECORDED
|
|
29
|
-
const isStreamLive = liveInfo.type === PUBLIC_LIVE_MODE.LIVING && (liveInfo.sub_type === SUB_TYPE.OUTSIDE || liveInfo.sub_type === SUB_TYPE.REBROADCAST)
|
|
30
30
|
|
|
31
31
|
// 当前时间是否在回放时间开始前, 如果没有回放开始时间, 则直接判断未回放还没生成
|
|
32
32
|
const isBeforeRecordTime = liveInfo.replay_begin_time
|
|
@@ -45,6 +45,7 @@ const shouldfixedLoading = window.navigator.userAgent.indexOf('iPad') > -1
|
|
|
45
45
|
|| isInWX()
|
|
46
46
|
|
|
47
47
|
export default function LiveVideo({
|
|
48
|
+
isStreamLive,
|
|
48
49
|
handleLogin,
|
|
49
50
|
userInfo,
|
|
50
51
|
liveInfo,
|
|
@@ -168,6 +169,7 @@ export default function LiveVideo({
|
|
|
168
169
|
{showAliPlayer && <AliPlayer options={options} onReady={handleVideoReady} />}
|
|
169
170
|
{supportM3u8 && (
|
|
170
171
|
<LiveStatus
|
|
172
|
+
isStreamLive={isStreamLive}
|
|
171
173
|
handleLogin={handleLogin}
|
|
172
174
|
userInfo={userInfo}
|
|
173
175
|
visitTime={visitTime}
|
|
@@ -8,6 +8,7 @@ import LiveStatus from '../LiveStatus'
|
|
|
8
8
|
import style from './index.module.less'
|
|
9
9
|
|
|
10
10
|
export default function RecordVideo({
|
|
11
|
+
isStreamLive,
|
|
11
12
|
userInfo,
|
|
12
13
|
liveInfo,
|
|
13
14
|
visitTime,
|
|
@@ -133,6 +134,7 @@ export default function RecordVideo({
|
|
|
133
134
|
onReady={handleVideoReady}
|
|
134
135
|
/>
|
|
135
136
|
<LiveStatus
|
|
137
|
+
isStreamLive={isStreamLive}
|
|
136
138
|
userInfo={userInfo}
|
|
137
139
|
visitTime={visitTime}
|
|
138
140
|
diffTime={diffTime}
|
package/src/detail/index.jsx
CHANGED
|
@@ -11,10 +11,9 @@ import {
|
|
|
11
11
|
import { getIMLiveInfo, getGuestIMLiveInfo } from '@/service/imBroadcasts'
|
|
12
12
|
import Loading from '@/component/status/Loading'
|
|
13
13
|
import {
|
|
14
|
-
PUBLIC_LIVE_STATUS, PUBLIC_LIVE_MODE,
|
|
14
|
+
PUBLIC_LIVE_STATUS, PUBLIC_LIVE_MODE, SUB_TYPE
|
|
15
15
|
} from '@/config/publicLive'
|
|
16
16
|
import { getUrlQuery } from '@/util/url'
|
|
17
|
-
import ImPush from '@/util/push'
|
|
18
17
|
import { getRecordLiveStatus } from '@/util/live'
|
|
19
18
|
import { isEmpty } from '@/util/object'
|
|
20
19
|
// import IMChatroom from '@/component/IMChatroom'
|
|
@@ -79,7 +78,6 @@ export default function PublicLiveDetail({
|
|
|
79
78
|
const isLiveToReplay = !replay
|
|
80
79
|
const isStreamLive = liveInfo
|
|
81
80
|
&& liveInfo.type === PUBLIC_LIVE_MODE.LIVING
|
|
82
|
-
&& (liveInfo.sub_type === SUB_TYPE.OUTSIDE || liveInfo.sub_type === SUB_TYPE.REBROADCAST)
|
|
83
81
|
|
|
84
82
|
const handleStatusChange = async (status) => {
|
|
85
83
|
const newLiveInfo = {
|
|
@@ -197,12 +195,6 @@ export default function PublicLiveDetail({
|
|
|
197
195
|
}
|
|
198
196
|
data.imInfo = imLiveInfoResp
|
|
199
197
|
}
|
|
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
198
|
// 如果是转播或者是推流 直接播放(用于调试模式)
|
|
207
199
|
const { preview } = getUrlQuery() // 后台点预览会加这个参数
|
|
208
200
|
const generateInfo = preview ? Object.assign(data, {
|
|
@@ -213,27 +205,6 @@ export default function PublicLiveDetail({
|
|
|
213
205
|
init()
|
|
214
206
|
}, [])
|
|
215
207
|
|
|
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
208
|
useEffect(() => {
|
|
238
209
|
if (userInfo) {
|
|
239
210
|
onReportProgress()
|
|
@@ -410,6 +381,7 @@ export default function PublicLiveDetail({
|
|
|
410
381
|
: isRecordLive
|
|
411
382
|
? (
|
|
412
383
|
<RecordVideo
|
|
384
|
+
isStreamLive={isStreamLive}
|
|
413
385
|
userInfo={userInfo}
|
|
414
386
|
liveInfo={liveInfo}
|
|
415
387
|
visitTime={visitTime}
|
|
@@ -426,6 +398,7 @@ export default function PublicLiveDetail({
|
|
|
426
398
|
)
|
|
427
399
|
: (
|
|
428
400
|
<LiveVideo
|
|
401
|
+
isStreamLive={isStreamLive}
|
|
429
402
|
handleLogin={handleLogin}
|
|
430
403
|
userInfo={userInfo}
|
|
431
404
|
liveInfo={liveInfo}
|
|
@@ -470,7 +443,8 @@ export default function PublicLiveDetail({
|
|
|
470
443
|
} */}
|
|
471
444
|
</div>
|
|
472
445
|
{
|
|
473
|
-
!isReplayMode && !isRecordLive
|
|
446
|
+
!isReplayMode && !isRecordLive
|
|
447
|
+
&& liveInfo.sub_type !== SUB_TYPE.NET_DRAGON
|
|
474
448
|
&& liveInfo.status !== PUBLIC_LIVE_STATUS.COMPLETEED
|
|
475
449
|
&& (
|
|
476
450
|
<LineSwitch
|
package/src/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { render } from 'react-dom'
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
const { PublicLiveDetail } = PublicLive
|
|
4
|
+
import Demo from './demo'
|
|
7
5
|
|
|
8
6
|
// 测试页面内容
|
|
9
7
|
render(
|
|
10
|
-
<
|
|
11
|
-
liveId="13aafbce-8ca2-4587-bc6e-eab183c9d5b6"
|
|
12
|
-
appId="e5649925-441d-4a53-b525-51a2f1c4e0a8"
|
|
13
|
-
/>,
|
|
8
|
+
<Demo />,
|
|
14
9
|
document.querySelector('#root')
|
|
15
10
|
)
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import style from './index.module.less'
|
|
5
|
+
|
|
6
|
+
export default function Empty({
|
|
7
|
+
tip = '暂无内容',
|
|
8
|
+
className
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<div className={classNames(style['empty-wrap'], className)}>
|
|
12
|
+
<div className={style['img-wrap']}>
|
|
13
|
+
<div>
|
|
14
|
+
<img src={require('./img/empty.png')} alt="" />
|
|
15
|
+
</div>
|
|
16
|
+
<div className={style.tip}>{tip}</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.empty-wrap {
|
|
2
|
+
margin-top: 100px;
|
|
3
|
+
|
|
4
|
+
.img-wrap {
|
|
5
|
+
padding: 16px;
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
|
|
11
|
+
img {
|
|
12
|
+
width: 260px;
|
|
13
|
+
height: 182px;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tip {
|
|
18
|
+
font-size: 16px;
|
|
19
|
+
color: #666;
|
|
20
|
+
line-height: 24px;
|
|
21
|
+
margin-top: 32px;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { message } from 'fish'
|
|
4
|
+
import { find } from 'lodash'
|
|
5
|
+
import { openLiveSubscribe } from '@/service/live'
|
|
6
|
+
import style from './index.module.less'
|
|
7
|
+
|
|
8
|
+
const Actions = {
|
|
9
|
+
1: '进入直播', // 直播中 或者开播前15min
|
|
10
|
+
2: '观看回放', // 回放
|
|
11
|
+
3: '预约', // 预告 且开播时间大于 15min
|
|
12
|
+
4: '已预约'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function Action({
|
|
16
|
+
data,
|
|
17
|
+
subscription,
|
|
18
|
+
onActionDetailClick,
|
|
19
|
+
handleLogin,
|
|
20
|
+
isLogin,
|
|
21
|
+
onSubscribe
|
|
22
|
+
}) {
|
|
23
|
+
const { status, live_id: liveId, begin_time: beginTime } = data
|
|
24
|
+
const [curAction, setCurAction] = useState(() => {
|
|
25
|
+
let actionNum
|
|
26
|
+
if (status === 1) {
|
|
27
|
+
actionNum = 1
|
|
28
|
+
} else if (status === 2) {
|
|
29
|
+
actionNum = 2
|
|
30
|
+
} else { // status = 0
|
|
31
|
+
// 如果超过了开播时间,不管有没有预约,都直接进入直播
|
|
32
|
+
const now = new Date().getTime()
|
|
33
|
+
const begin = new Date(beginTime).getTime()
|
|
34
|
+
if (now > begin) {
|
|
35
|
+
actionNum = 1
|
|
36
|
+
return actionNum
|
|
37
|
+
}
|
|
38
|
+
// 开播前15分钟,只提供进入直播按钮
|
|
39
|
+
if (begin > now && (begin - now) < 15 * 60 * 1000) {
|
|
40
|
+
actionNum = 1
|
|
41
|
+
return actionNum
|
|
42
|
+
}
|
|
43
|
+
// 开播前15分钟之外
|
|
44
|
+
const subscriptionItem = find(subscription, {
|
|
45
|
+
live_id: liveId
|
|
46
|
+
})
|
|
47
|
+
if (subscriptionItem?.is_subscribe) { // 已预约
|
|
48
|
+
actionNum = 4
|
|
49
|
+
} else { // 未预约
|
|
50
|
+
actionNum = 3
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return actionNum
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const handleBtnClick = async (e) => {
|
|
57
|
+
e.stopPropagation()
|
|
58
|
+
if (curAction === 3) {
|
|
59
|
+
try {
|
|
60
|
+
if (!isLogin) {
|
|
61
|
+
handleLogin(data)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
onSubscribe(data)
|
|
65
|
+
await openLiveSubscribe({
|
|
66
|
+
liveId
|
|
67
|
+
})
|
|
68
|
+
message.success('预约成功')
|
|
69
|
+
const now = new Date().getTime()
|
|
70
|
+
const begin = new Date(beginTime).getTime()
|
|
71
|
+
if (begin > now && (begin - now) < 15 * 60 * 1000) {
|
|
72
|
+
setCurAction(1)
|
|
73
|
+
} else {
|
|
74
|
+
setCurAction(4)
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error?.response?.data?.message === '直播开始前15分钟无法预约') {
|
|
78
|
+
setCurAction(1)
|
|
79
|
+
}
|
|
80
|
+
message.error(error?.response?.data?.message || '预约失败,请稍后重试')
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
onActionDetailClick()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div
|
|
89
|
+
className={classNames(style.action, {
|
|
90
|
+
[style['action-subscribe']]: curAction === 3,
|
|
91
|
+
[style['action-has-subscribe']]: curAction === 4
|
|
92
|
+
})}
|
|
93
|
+
onClick={handleBtnClick}
|
|
94
|
+
>
|
|
95
|
+
{Actions[curAction]}
|
|
96
|
+
</div>
|
|
97
|
+
)
|
|
98
|
+
}
|