129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import { useState } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import {
|
|
Card, Form, Input, Button, DatePicker, Typography, message, Space, Alert,
|
|
} from 'antd'
|
|
import { CopyOutlined, ArrowLeftOutlined } from '@ant-design/icons'
|
|
import { createStream } from '../../api/streams'
|
|
|
|
const { Title, Text } = Typography
|
|
const { TextArea } = Input
|
|
|
|
export default function StreamForm() {
|
|
const [loading, setLoading] = useState(false)
|
|
const [result, setResult] = useState<{ rtmp_url: string; stream_key: string } | null>(null)
|
|
const navigate = useNavigate()
|
|
|
|
const handleSubmit = async (values: any) => {
|
|
setLoading(true)
|
|
try {
|
|
const res = await createStream({
|
|
title: values.title,
|
|
description: values.description,
|
|
cover_url: values.cover_url,
|
|
scheduled_at: values.scheduled_at?.toISOString(),
|
|
})
|
|
setResult({ rtmp_url: res.rtmp_url, stream_key: res.stream_key })
|
|
message.success('直播已创建')
|
|
} catch {
|
|
message.error('创建失败')
|
|
}
|
|
setLoading(false)
|
|
}
|
|
|
|
if (result) {
|
|
return (
|
|
<div style={{ maxWidth: 640 }}>
|
|
<Title level={3} style={{ marginBottom: 24 }}>直播已创建</Title>
|
|
<Alert
|
|
type="success"
|
|
message="推流信息已生成"
|
|
description={
|
|
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
|
<div>
|
|
<Text strong>推流码 (UUID):</Text>
|
|
<div style={{
|
|
marginTop: 8, padding: 12,
|
|
background: '#F5F2EE', borderRadius: 6,
|
|
fontFamily: 'monospace', fontSize: 14,
|
|
wordBreak: 'break-all',
|
|
}}>
|
|
{result.stream_key}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<Text strong>RTMP 推流地址:</Text>
|
|
<div style={{
|
|
marginTop: 8, padding: 12,
|
|
background: '#F5F2EE', borderRadius: 6,
|
|
fontFamily: 'monospace', fontSize: 14,
|
|
wordBreak: 'break-all',
|
|
}}>
|
|
{result.rtmp_url}
|
|
</div>
|
|
</div>
|
|
</Space>
|
|
}
|
|
showIcon
|
|
style={{ marginBottom: 24 }}
|
|
/>
|
|
<Space>
|
|
<Button
|
|
icon={<CopyOutlined />}
|
|
onClick={() => {
|
|
navigator.clipboard.writeText(
|
|
`推流码: ${result.stream_key}\nRTMP 地址: ${result.rtmp_url}`
|
|
)
|
|
message.success('已复制到剪贴板')
|
|
}}
|
|
>
|
|
复制全部
|
|
</Button>
|
|
<Button type="primary" onClick={() => navigate('/admin/streams')}>
|
|
返回列表
|
|
</Button>
|
|
</Space>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div style={{ maxWidth: 640 }}>
|
|
<Button
|
|
type="text"
|
|
icon={<ArrowLeftOutlined />}
|
|
onClick={() => navigate('/admin/streams')}
|
|
style={{ marginBottom: 16 }}
|
|
>
|
|
返回
|
|
</Button>
|
|
<Card>
|
|
<Title level={3} style={{ marginBottom: 24 }}>创建直播</Title>
|
|
<Form layout="vertical" onFinish={handleSubmit}>
|
|
<Form.Item
|
|
name="title"
|
|
label="直播标题"
|
|
rules={[{ required: true, message: '请输入直播标题' }]}
|
|
>
|
|
<Input placeholder="输入直播标题" size="large" />
|
|
</Form.Item>
|
|
<Form.Item name="description" label="直播简介">
|
|
<TextArea rows={3} placeholder="可选,直播内容简介" />
|
|
</Form.Item>
|
|
<Form.Item name="cover_url" label="封面图片地址">
|
|
<Input placeholder="https://..." />
|
|
</Form.Item>
|
|
<Form.Item name="scheduled_at" label="预定开播时间">
|
|
<DatePicker showTime style={{ width: '100%' }} size="large" placeholder="选择预定时间" />
|
|
</Form.Item>
|
|
<Form.Item>
|
|
<Button type="primary" htmlType="submit" loading={loading} size="large" block>
|
|
创建直播
|
|
</Button>
|
|
</Form.Item>
|
|
</Form>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|