diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f434378..63854ff 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -10,6 +10,7 @@ import StreamList from './admin/pages/StreamList' import StreamForm from './admin/pages/StreamForm' import NodeManager from './admin/pages/NodeManager' import SettingsPage from './admin/pages/Settings' +import HomePage from './viewer/pages/HomePage' import WatchPage from './viewer/pages/WatchPage' import { verifyToken } from './api/auth' import { getToken } from './api/client' @@ -46,7 +47,7 @@ export default function App() { } /> } /> - } /> + } /> diff --git a/frontend/src/viewer/pages/HomePage.tsx b/frontend/src/viewer/pages/HomePage.tsx new file mode 100644 index 0000000..4974561 --- /dev/null +++ b/frontend/src/viewer/pages/HomePage.tsx @@ -0,0 +1,126 @@ +import { useState, useEffect } from 'react' +import { useNavigate } from 'react-router-dom' +import { + Layout, Row, Col, Card, Typography, Tag, Button, Skeleton, Empty, Space, +} from 'antd' +import { LoginOutlined, FireOutlined, ClockCircleOutlined } from '@ant-design/icons' +import { fetchStreams, type StreamInfo } from '../api/streams' + +const { Header, Content } = Layout +const { Title, Text } = Typography + +const statusMeta: Record = { + live: { color: 'red', label: '直播中', icon: }, + pending: { color: 'blue', label: '待开播', icon: }, + ended: { color: 'default', label: '已结束', icon: null }, + cancelled: { color: 'default', label: '已取消', icon: null }, +} + +export default function HomePage() { + const [streams, setStreams] = useState([]) + const [loading, setLoading] = useState(true) + const navigate = useNavigate() + + useEffect(() => { + fetchStreams() + .then(setStreams) + .catch(() => {}) + .finally(() => setLoading(false)) + }, []) + + const sorted = [...streams].sort((a, b) => { + const order: Record = { live: 0, pending: 1, ended: 2, cancelled: 3 } + return (order[a.status] ?? 9) - (order[b.status] ?? 9) + }) + + return ( + +
+ + LiveStream + <Text type="secondary" style={{ fontSize: 14, marginLeft: 10, fontWeight: 400 }}> + 简易直播平台 + </Text> + + +
+ + 全部直播 + + {loading ? ( + + {[1,2,3,4,5,6].map((i) => ( + + + + ))} + + ) : sorted.length === 0 ? ( + + ) : ( + + {sorted.map((s) => { + const meta = statusMeta[s.status] ?? statusMeta.pending + return ( + + + {!s.cover_url && ( + + {s.status === 'live' ? : '🎬'} + + )} + + } + onClick={() => navigate(`/watch/${s.id}`)} + > + + + {meta.icon} {meta.label} + + {s.title} + + } + description={ + s.description + ? {s.description} + : 暂无简介 + } + /> + + + ) + })} + + )} + +
+ ) +}