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
+
+ 简易直播平台
+
+
+ }
+ onClick={() => navigate('/admin')}
+ >
+ 管理后台
+
+
+
+ 全部直播
+
+ {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}
+ : 暂无简介
+ }
+ />
+
+
+ )
+ })}
+
+ )}
+
+
+ )
+}