品牌化重构: StreamCore + 现代UI主题 + 英文界面

- 移除所有emoji (HomePage中的🎬改为VideoCameraOutlined图标)
- 主题重设计: 深蓝色系主色(#1E3A5F),系统sans-serif字体
  白色/浅灰背景,现代卡片阴影和圆角,完全去除复古感
- 首页移除管理入口,纯观众视角(渐变横幅+卡片列表)
- 统一品牌名称 StreamCore (替换LiveStream)
- 全部界面英文(antd默认locale,去除zhCN)
- 登录页渐变+卡片居中布局
This commit is contained in:
admin committed 2026-08-10 14:40:58 +08:00
1 parent b81a7bf293
commit 5f19fc6aa5
14 files changed
+253 -225

No files matched your search

+26 -23
View File
@@ -9,10 +9,10 @@ import { fetchStreams, deleteStream, goLive, endStream, type StreamInfo } from '
const { Title, Text } = Typography
const statusMap: Record<string, { color: string; label: string }> = {
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' },
}
export default function StreamList() {
@@ -27,47 +27,50 @@ export default function StreamList() {
try {
const data = await fetchStreams()
setStreams(data)
} catch { message.error('加载失败') }
} catch { message.error('Failed to load streams') }
setLoading(false)
}
async function handleDelete(id: number) {
try {
await deleteStream(id)
message.success('已删除')
message.success('Deleted')
loadData()
} catch { message.error('删除失败') }
} catch { message.error('Failed to delete') }
}
async function handleGoLive(id: number) {
try {
await goLive(id)
message.success('已设置为直播中')
message.success('Stream is now live')
loadData()
} catch { message.error('操作失败') }
} catch { message.error('Operation failed') }
}
async function handleEnd(id: number) {
try {
await endStream(id)
message.success('已结束直播')
message.success('Stream ended')
loadData()
} catch { message.error('操作失败') }
} catch { message.error('Operation failed') }
}
const columns = [
{ title: 'ID', dataIndex: 'id', key: 'id', width: 80 },
{ title: '标题', dataIndex: 'title', key: 'title', ellipsis: true },
{ title: 'Title', dataIndex: 'title', key: 'title', ellipsis: true },
{
title: '状态', dataIndex: 'status', key: 'status', width: 100,
title: 'Status', dataIndex: 'status', key: 'status', width: 110,
render: (s: string) => {
const info = statusMap[s] || { color: 'default', label: s }
return <Tag color={info.color}>{info.label}</Tag>
},
},
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (v: string) => v?.slice(0, 16), width: 170 },
{
title: '操作', key: 'actions', width: 280,
title: 'Created', dataIndex: 'created_at', key: 'created_at',
render: (v: string) => v?.slice(0, 16), width: 170,
},
{
title: 'Actions', key: 'actions', width: 280,
render: (_: any, record: StreamInfo) => (
<Space size="small">
<Button
@@ -75,26 +78,26 @@ export default function StreamList() {
icon={<LinkOutlined />}
onClick={() => {
navigator.clipboard.writeText(record.stream_key)
message.success('推流码已复制')
message.success('Stream key copied')
}}
>
复制推流码
Copy Key
</Button>
{record.status !== 'live' ? (
<Tooltip title="切换为直播中">
<Tooltip title="Go Live">
<Button size="small" type="primary" icon={<PlayCircleOutlined />}
onClick={() => handleGoLive(record.id)} ghost />
</Tooltip>
) : (
<Tooltip title="结束直播">
<Tooltip title="End Stream">
<Button size="small" icon={<StopOutlined />}
onClick={() => handleEnd(record.id)} danger />
</Tooltip>
)}
<Button size="small" onClick={() => window.open(`/watch/${record.id}`, '_blank')}>
观看
Watch
</Button>
<Popconfirm title="确定删除这条直播?" onConfirm={() => handleDelete(record.id)}>
<Popconfirm title="Delete this stream?" onConfirm={() => handleDelete(record.id)}>
<Button size="small" icon={<DeleteOutlined />} danger />
</Popconfirm>
</Space>
@@ -105,9 +108,9 @@ export default function StreamList() {
return (
<div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
<Title level={3} style={{ margin: 0 }}>直播列表</Title>
<Title level={3} style={{ margin: 0, fontWeight: 600 }}>Streams</Title>
<Button type="primary" icon={<PlusOutlined />} onClick={() => navigate('/admin/streams/new')}>
创建直播
New Stream
</Button>
</div>
<Table