diff --git a/backend/main.py b/backend/main.py index a83b80b..99eaea5 100644 --- a/backend/main.py +++ b/backend/main.py @@ -19,7 +19,7 @@ async def lifespan(app: FastAPI): transcode_mgr.stop_all() -app = FastAPI(title="LiveStream Platform", lifespan=lifespan) +app = FastAPI(title="StreamCore", lifespan=lifespan) app.add_middleware( CORSMiddleware, diff --git a/frontend/index.html b/frontend/index.html index bdb7cf8..77805a7 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,10 +3,7 @@ - LiveStream Platform - - - + StreamCore
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 63854ff..0ea8dbb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,6 @@ import { useState, useEffect } from 'react' import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import { ConfigProvider } from 'antd' -import zhCN from 'antd/locale/zh_CN' import theme from './theme/anthropic' import AdminLayout from './admin/AdminLayout' import LoginPage from './admin/LoginPage' @@ -31,7 +30,7 @@ function AdminGuard({ children }: { children: React.ReactNode }) { export default function App() { return ( - + } /> diff --git a/frontend/src/admin/AdminLayout.tsx b/frontend/src/admin/AdminLayout.tsx index 9d8f7b8..5a6b73a 100644 --- a/frontend/src/admin/AdminLayout.tsx +++ b/frontend/src/admin/AdminLayout.tsx @@ -15,11 +15,11 @@ const { Sider, Content, Header } = Layout const { Text } = Typography const menuItems = [ - { key: '/admin', icon: , label: '概览' }, - { key: '/admin/streams', icon: , label: '直播列表' }, - { key: '/admin/streams/new', icon: , label: '创建直播' }, - { key: '/admin/nodes', icon: , label: '边缘节点' }, - { key: '/admin/settings', icon: , label: '系统设置' }, + { key: '/admin', icon: , label: 'Dashboard' }, + { key: '/admin/streams', icon: , label: 'Streams' }, + { key: '/admin/streams/new', icon: , label: 'New Stream' }, + { key: '/admin/nodes', icon: , label: 'Nodes' }, + { key: '/admin/settings', icon: , label: 'Settings' }, ] export default function AdminLayout() { @@ -44,7 +44,7 @@ export default function AdminLayout() { onCollapse={setCollapsed} width={220} style={{ - borderRight: '1px solid #E8E4DD', + borderRight: '1px solid #E8ECF1', background: '#FFFFFF', }} > @@ -53,10 +53,16 @@ export default function AdminLayout() { display: 'flex', alignItems: 'center', justifyContent: 'center', - borderBottom: '1px solid #E8E4DD', + borderBottom: '1px solid #E8ECF1', + background: '#1E3A5F', + color: '#FFFFFF', }}> - - {collapsed ? 'LS' : 'LiveStream'} + + {collapsed ? 'SC' : 'StreamCore'}
} onClick={handleLogout} > - 退出登录 + Logout
diff --git a/frontend/src/admin/LoginPage.tsx b/frontend/src/admin/LoginPage.tsx index 6613f08..f3d1750 100644 --- a/frontend/src/admin/LoginPage.tsx +++ b/frontend/src/admin/LoginPage.tsx @@ -14,10 +14,10 @@ export default function LoginPage() { setLoading(true) try { await login(values.password) - message.success('登录成功') + message.success('Login successful') navigate('/admin') } catch { - message.error('密码错误') + message.error('Invalid password') } finally { setLoading(false) } @@ -29,28 +29,28 @@ export default function LoginPage() { display: 'flex', alignItems: 'center', justifyContent: 'center', - background: '#FAF8F5', + background: 'linear-gradient(135deg, #1E3A5F 0%, #2D5F8A 50%, #F5F6FA 50%)', }}> - +
- LiveStream - 管理后台 + StreamCore + Admin Console
} - placeholder="密码" + placeholder="Password" size="large" />
diff --git a/frontend/src/admin/pages/Dashboard.tsx b/frontend/src/admin/pages/Dashboard.tsx index e33a4f7..03b5d23 100644 --- a/frontend/src/admin/pages/Dashboard.tsx +++ b/frontend/src/admin/pages/Dashboard.tsx @@ -1,9 +1,9 @@ import { useState, useEffect } from 'react' import { Row, Col, Card, Statistic, Typography, Table, Tag, Space } from 'antd' -import { VideoCameraOutlined, EyeOutlined, SignalFilled } from '@ant-design/icons' +import { VideoCameraOutlined, SignalFilled, PlayCircleOutlined } from '@ant-design/icons' import { fetchStreams, type StreamInfo } from '../../api/streams' -const { Title } = Typography +const { Title, Text } = Typography export default function Dashboard() { const [streams, setStreams] = useState([]) @@ -27,60 +27,65 @@ export default function Dashboard() { const pendingCount = streams.filter((s) => s.status === 'pending').length const statusMap: Record = { - pending: { color: 'blue', label: '待开播' }, - live: { color: 'green', label: '直播中' }, - ended: { color: 'default', label: '已结束' }, - cancelled: { color: 'red', label: '已取消' }, + pending: { color: 'blue', label: 'Scheduled' }, + live: { color: 'green', label: 'Live' }, + ended: { color: 'default', label: 'Ended' }, + cancelled: { color: 'red', label: 'Cancelled' }, } const recentColumns = [ - { title: '标题', dataIndex: 'title', key: 'title', ellipsis: true }, + { title: 'Title', dataIndex: 'title', key: 'title', ellipsis: true }, { - title: '状态', dataIndex: 'status', key: 'status', + title: 'Status', dataIndex: 'status', key: 'status', render: (status: string) => { const s = statusMap[status] || { color: 'default', label: status } return {s.label} }, + width: 110, + }, + { + title: 'Created', dataIndex: 'created_at', key: 'created_at', + render: (v: string) => v?.slice(0, 16), + width: 170, }, - { title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (v: string) => v?.slice(0, 16) }, ] return (
- 概览 + Overview - + } + prefix={} loading={loading} /> - + } + prefix={} loading={loading} /> - + } + prefix={} loading={loading} /> - + = { - 'round-robin': '轮询', - 'weighted': '权重', - 'least-conn': '最少连接', + 'round-robin': 'Round-Robin', + 'weighted': 'Weighted', + 'least-conn': 'Least-Conn', } export default function NodeManager() { @@ -45,15 +45,15 @@ export default function NodeManager() { ]) setNodes(nodesRes.data) setStrategy(strategyRes.data) - } catch { message.error('加载失败') } + } catch { message.error('Failed to load') } setLoading(false) } async function updateWeight(nodeId: string, weight: number) { try { await api.put(`/nodes/${nodeId}`, { weight }) - message.success('已更新') - } catch { message.error('更新失败') } + message.success('Updated') + } catch { message.error('Failed') } } async function toggleNode(nodeId: string, enabled: boolean) { @@ -62,17 +62,17 @@ export default function NodeManager() { try { await api.put(`/nodes/${nodeId}`, { weight: node.weight, enabled }) setNodes((prev) => prev.map((n) => (n.id === nodeId ? { ...n, enabled } : n))) - message.success('已更新') - } catch { message.error('更新失败') } + message.success('Updated') + } catch { message.error('Failed') } } const columns = [ - { title: '名称', dataIndex: 'name', key: 'name' }, - { title: '主机', dataIndex: 'host', key: 'host' }, - { title: 'HLS 端口', dataIndex: 'hls_port', key: 'hls_port', width: 100 }, - { title: 'API 端口', dataIndex: 'api_port', key: 'api_port', width: 100 }, + { title: 'Name', dataIndex: 'name', key: 'name' }, + { title: 'Host', dataIndex: 'host', key: 'host' }, + { title: 'HLS Port', dataIndex: 'hls_port', key: 'hls_port', width: 100 }, + { title: 'API Port', dataIndex: 'api_port', key: 'api_port', width: 100 }, { - title: '权重', dataIndex: 'weight', key: 'weight', width: 140, + title: 'Weight', dataIndex: 'weight', key: 'weight', width: 140, render: (_: number, record: NodeInfo) => ( ( } color="success">在线, + title: 'Health', key: 'health', width: 100, + render: () => } color="success">Online, }, ] return (
- 边缘节点管理 + Edge Nodes {strategy && (
- + - + - - + + )} } onClick={loadData}>刷新} + title="Node List" + extra={} + style={{ borderRadius: 12 }} >
- 系统设置 + System Settings - - - + + + + - -