8c31cecb37
数据大盘新增/增强两块运营配置: - 首页轮播种子(新):列表/新增/编辑/批量生成/预览效果;用户名可空(留空自动合成)、金额区间(min~max) - 首页数据配置(增强):自增长「百分比/固定增量」切换、真实值基数偏移、「允许数字下降」(只增不减)开关、下次预计值、立即更新二次确认;倍率上限 1.5 - 依赖 @ant-design/v5-patch-for-react-19(React 19 兼容,providers 顶部 import) - start.sh/stop.sh 跨平台重写;.run-logs/ 加入 .gitignore Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { Alert, Card, Col, Row, Spin, Statistic } from 'antd';
|
|
import { api } from '@/lib/api';
|
|
import type { DashboardOverview } from '@/lib/types';
|
|
import HomeStatsConfig from './HomeStatsConfig';
|
|
import HomeMarqueeSeeds from './HomeMarqueeSeeds';
|
|
|
|
const yuan = (cents: number) => `¥${(cents / 100).toFixed(2)}`;
|
|
|
|
export default function DashboardPage() {
|
|
const [data, setData] = useState<DashboardOverview | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
api
|
|
.get<DashboardOverview>('/admin/api/stats/overview')
|
|
.then((r) => setData(r.data))
|
|
.finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
if (loading || !data) return <Spin style={{ display: 'block', marginTop: 80 }} />;
|
|
|
|
const cards: { title: string; value: string | number; suffix?: string; danger?: boolean }[] = [
|
|
{ title: '总用户', value: data.users.total },
|
|
{ title: '今日活跃 DAU', value: data.users.dau },
|
|
{ title: '今日新增', value: data.users.new_today },
|
|
{ title: '封禁用户', value: data.users.disabled, danger: data.users.disabled > 0 },
|
|
{ title: '累计发放金币', value: data.coins.granted_total },
|
|
{ title: '累计成功提现', value: yuan(data.cash.withdraw_success_cents) },
|
|
{ title: '待处理提现', value: data.cash.withdraw_pending_count, danger: data.cash.withdraw_pending_count > 0 },
|
|
{ title: '比价成功率', value: (data.comparison.success_rate * 100).toFixed(1), suffix: '%' },
|
|
{ title: '比价总次数', value: data.comparison.total },
|
|
{ title: '待处理反馈', value: data.feedback.new, danger: data.feedback.new > 0 },
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<h2>数据大盘</h2>
|
|
<Row gutter={[16, 16]}>
|
|
{cards.map((c) => (
|
|
<Col key={c.title} xs={12} sm={8} md={6} xl={4}>
|
|
<Card>
|
|
<Statistic
|
|
title={c.title}
|
|
value={c.value}
|
|
suffix={c.suffix}
|
|
valueStyle={c.danger ? { color: '#cf1322' } : undefined}
|
|
/>
|
|
</Card>
|
|
</Col>
|
|
))}
|
|
</Row>
|
|
{!data.cps.available && (
|
|
<Alert style={{ marginTop: 16 }} type="info" showIcon message={`CPS 收入:${data.cps.note}`} />
|
|
)}
|
|
<HomeStatsConfig />
|
|
<HomeMarqueeSeeds />
|
|
</div>
|
|
);
|
|
}
|