Files
live/frontend/src/admin/pages/StreamForm.tsx
T
2026-08-07 15:04:19 +08:00

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>
)
}