134 lines
3.9 KiB
TypeScript
134 lines
3.9 KiB
TypeScript
import { Card, Col, Row, Space, Statistic, Tag, Typography, theme } from 'antd';
|
|
import { useEffect, useMemo, useState } from 'react';
|
|
import { dashboardApi } from '../api/modules';
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
interface PlatformStats {
|
|
accounts: number;
|
|
tasks: number;
|
|
success: number;
|
|
failed: number;
|
|
}
|
|
|
|
interface DashboardStats {
|
|
douyu: PlatformStats & {
|
|
cookies: number;
|
|
};
|
|
huya: PlatformStats & {
|
|
goods: number;
|
|
rechargeGoods: number;
|
|
};
|
|
}
|
|
|
|
const EMPTY_STATS: DashboardStats = {
|
|
douyu: {
|
|
accounts: 0,
|
|
tasks: 0,
|
|
success: 0,
|
|
failed: 0,
|
|
cookies: 0,
|
|
},
|
|
huya: {
|
|
accounts: 0,
|
|
tasks: 0,
|
|
success: 0,
|
|
failed: 0,
|
|
goods: 0,
|
|
rechargeGoods: 0,
|
|
},
|
|
};
|
|
|
|
function StatCard({
|
|
title,
|
|
value,
|
|
color,
|
|
loading,
|
|
}: {
|
|
title: string;
|
|
value: number;
|
|
color?: string;
|
|
loading?: boolean;
|
|
}) {
|
|
return (
|
|
<Col xs={24} sm={12} lg={6}>
|
|
<Card size="small" loading={loading}>
|
|
<Statistic title={title} value={value} styles={{ content: color ? { color } : undefined }} />
|
|
</Card>
|
|
</Col>
|
|
);
|
|
}
|
|
|
|
export default function DashboardPage() {
|
|
const { token } = theme.useToken();
|
|
const [loading, setLoading] = useState(true);
|
|
const [stats, setStats] = useState<DashboardStats>(EMPTY_STATS);
|
|
|
|
useEffect(() => {
|
|
let ignore = false;
|
|
|
|
async function loadDashboard() {
|
|
setLoading(true);
|
|
try {
|
|
const data = await dashboardApi.summary();
|
|
if (!ignore) setStats(data);
|
|
} finally {
|
|
if (!ignore) setLoading(false);
|
|
}
|
|
}
|
|
|
|
void loadDashboard();
|
|
return () => {
|
|
ignore = true;
|
|
};
|
|
}, []);
|
|
|
|
const totalStats = useMemo(() => ({
|
|
accounts: stats.douyu.accounts + stats.huya.accounts,
|
|
tasks: stats.douyu.tasks + stats.huya.tasks,
|
|
success: stats.douyu.success + stats.huya.success,
|
|
failed: stats.douyu.failed + stats.huya.failed,
|
|
}), [stats]);
|
|
|
|
return (
|
|
<div>
|
|
<div style={{ marginBottom: 16 }}>
|
|
<Space align="center" wrap>
|
|
<Title level={2} style={{ margin: 0 }}>概览</Title>
|
|
<Tag color="blue">斗鱼</Tag>
|
|
<Tag color="orange">虎牙</Tag>
|
|
</Space>
|
|
</div>
|
|
|
|
<Row gutter={[12, 12]} style={{ marginBottom: 20 }}>
|
|
<StatCard title="账号总数" value={totalStats.accounts} loading={loading} />
|
|
<StatCard title="任务总数" value={totalStats.tasks} loading={loading} />
|
|
<StatCard title="成功任务" value={totalStats.success} color={token.colorSuccess} loading={loading} />
|
|
<StatCard title="失败任务" value={totalStats.failed} color={token.colorError} loading={loading} />
|
|
</Row>
|
|
|
|
<div style={{ marginBottom: 10 }}>
|
|
<Title level={4} style={{ margin: 0 }}>斗鱼</Title>
|
|
<Text type="secondary">账号登录、Cookie 产出和批量登录任务</Text>
|
|
</div>
|
|
<Row gutter={[12, 12]} style={{ marginBottom: 20 }}>
|
|
<StatCard title="斗鱼账号" value={stats.douyu.accounts} loading={loading} />
|
|
<StatCard title="登录任务" value={stats.douyu.tasks} loading={loading} />
|
|
<StatCard title="成功 Cookie" value={stats.douyu.cookies} color={token.colorSuccess} loading={loading} />
|
|
<StatCard title="失败/异常" value={stats.douyu.failed} color={token.colorError} loading={loading} />
|
|
</Row>
|
|
|
|
<div style={{ marginBottom: 10 }}>
|
|
<Title level={4} style={{ margin: 0 }}>虎牙</Title>
|
|
<Text type="secondary">账号 Cookie、活动任务、兑换商品和充值商品</Text>
|
|
</div>
|
|
<Row gutter={[12, 12]}>
|
|
<StatCard title="虎牙账号" value={stats.huya.accounts} loading={loading} />
|
|
<StatCard title="虎牙任务" value={stats.huya.tasks} loading={loading} />
|
|
<StatCard title="兑换商品" value={stats.huya.goods} loading={loading} />
|
|
<StatCard title="充值商品" value={stats.huya.rechargeGoods} loading={loading} />
|
|
</Row>
|
|
</div>
|
|
);
|
|
}
|