UI全面精雕: 米兰色衬线体系 + 全页质感升级
主题层: - 更精细的色彩层级(primaryBg/hover/active等语义色) - 字号体系: heading1-5, fontSize 15 基准 - 控件高度 40/48/32 三档, 圆角 6/10 - 三层阴影分层, motionDuration 首页: - 大幅面渐变英雄区(64px padding, 40px 标题) - 直播卡片: 暖棕渐变封面, LIVE 脉冲红点标签 - 悬停 transform+shadow 过渡, 描边高亮 仪表盘: - 彩色顶部边框卡片(绿/蓝/棕), 品牌名+标语头部 登录页: - 48px 大内边距, 返回首页链接 直播列表: - 描述行内展示, 推流码截断, 操作图标组 节点页: - 发光圆点在线指示器, 三色 CPU/内存进度阈值 - 在线/离线统计, Origin 标签 播放页: - 暗色 #1A1815 背景, 毛玻璃顶栏 - 圆角视频容器, box-shadow 景深 - document.title 动态标题
This commit is contained in:
1 parent
d4a3742136
commit
f0b8c2d64f
8 files changed
+461
-218
No files matched your search
@@ -1,11 +1,13 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Row, Col, Card, Statistic, Typography, Table, Tag } from 'antd'
|
||||
import { VideoCameraOutlined, SignalFilled, PlayCircleOutlined } from '@ant-design/icons'
|
||||
import { Row, Col, Card, Statistic, Typography, Table, Tag, Skeleton } from 'antd'
|
||||
import { SignalFilled, ClockCircleOutlined, PlayCircleOutlined } from '@ant-design/icons'
|
||||
import { fetchStreams, type StreamInfo } from '../../api/streams'
|
||||
import { useBrand } from '../../brand/BrandContext'
|
||||
|
||||
const { Title } = Typography
|
||||
const { Title, Text } = Typography
|
||||
|
||||
export default function Dashboard() {
|
||||
const { brand } = useBrand()
|
||||
const [streams, setStreams] = useState<StreamInfo[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
@@ -16,15 +18,12 @@ export default function Dashboard() {
|
||||
}, [])
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const data = await fetchStreams()
|
||||
setStreams(data)
|
||||
} catch { /* ignore */ }
|
||||
try { setStreams(await fetchStreams()) } catch { /* */ }
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const liveCount = streams.filter((s) => s.status === 'live').length
|
||||
const pendingCount = streams.filter((s) => s.status === 'pending').length
|
||||
const liveCount = streams.filter(s => s.status === 'live').length
|
||||
const pendingCount = streams.filter(s => s.status === 'pending').length
|
||||
|
||||
const statusMap: Record<string, { color: string; label: string }> = {
|
||||
pending: { color: 'blue', label: '待开播' },
|
||||
@@ -35,45 +34,46 @@ export default function Dashboard() {
|
||||
|
||||
const columns = [
|
||||
{ title: '标题', dataIndex: 'title', key: 'title', ellipsis: true },
|
||||
{
|
||||
title: '状态', dataIndex: 'status', key: 'status', width: 100,
|
||||
render: (s: string) => {
|
||||
const m = statusMap[s] || { color: 'default', label: s }
|
||||
return <Tag color={m.color}>{m.label}</Tag>
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间', dataIndex: 'created_at', key: 'created_at',
|
||||
render: (v: string) => v?.slice(0, 16), width: 170,
|
||||
},
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 100,
|
||||
render: (s: string) => <Tag color={(statusMap[s] || {}).color}>{(statusMap[s] || { label: s }).label}</Tag> },
|
||||
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (v: string) => v?.slice(0, 16), width: 170 },
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Title level={3} style={{ marginBottom: 24 }}>概览</Title>
|
||||
<Row gutter={[24, 24]}>
|
||||
<div style={{ marginBottom: 32 }}>
|
||||
<Title level={2} style={{ margin: 0, fontWeight: 600 }}>{brand.brand_name}</Title>
|
||||
<Text type="secondary" style={{ fontSize: 15 }}>管理控制台</Text>
|
||||
</div>
|
||||
|
||||
<Row gutter={[28, 28]} style={{ marginBottom: 32 }}>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card style={{ borderRadius: 10 }}>
|
||||
<Statistic title="直播中" value={liveCount}
|
||||
prefix={<SignalFilled style={{ color: '#5B8C5A' }} />} loading={loading} />
|
||||
<Card style={{ borderRadius: 12, borderTop: '3px solid #5B8C5A' }}>
|
||||
<Statistic title="直播中" value={liveCount} loading={loading}
|
||||
prefix={<SignalFilled style={{ color: '#5B8C5A', fontSize: 18 }} />} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card style={{ borderRadius: 10 }}>
|
||||
<Statistic title="待开播" value={pendingCount}
|
||||
prefix={<VideoCameraOutlined style={{ color: '#6B8CA8' }} />} loading={loading} />
|
||||
<Card style={{ borderRadius: 12, borderTop: '3px solid #6B8CA8' }}>
|
||||
<Statistic title="待开播" value={pendingCount} loading={loading}
|
||||
prefix={<ClockCircleOutlined style={{ color: '#6B8CA8', fontSize: 18 }} />} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card style={{ borderRadius: 10 }}>
|
||||
<Statistic title="直播总数" value={streams.length}
|
||||
prefix={<PlayCircleOutlined />} loading={loading} />
|
||||
<Card style={{ borderRadius: 12, borderTop: '3px solid #C2693A' }}>
|
||||
<Statistic title="直播总数" value={streams.length} loading={loading}
|
||||
prefix={<PlayCircleOutlined style={{ color: '#C2693A', fontSize: 18 }} />} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Card title="最近直播" style={{ marginTop: 24, borderRadius: 10 }}>
|
||||
|
||||
<Card
|
||||
title={<Title level={4} style={{ margin: 0, fontWeight: 600 }}>最近直播</Title>}
|
||||
style={{ borderRadius: 12 }}
|
||||
>
|
||||
<Table dataSource={streams.slice(0, 10)} columns={columns}
|
||||
rowKey="id" loading={loading} pagination={false} size="middle" />
|
||||
rowKey="id" loading={loading} pagination={false} size="middle"
|
||||
locale={{ emptyText: '暂无直播数据' }} />
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user