Initial CMPP frontend prototype

This commit is contained in:
hectorzhao
2026-06-30 16:09:46 +08:00
commit 2f3c274a30
98 changed files with 25255 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
import { useMemo } from 'react';
import { BarChart3 } from 'lucide-react';
import { Button, Chart, Tag } from '@/components/ui';
import { auditTrend, channelShare, customerGrowth, hourlySendTrend } from '@/mock/chartData';
import { adminService } from '@/mock';
import { createBarOption, createLineOption, createPieOption } from '@/theme/chartOptions';
export function AdminAnalyticsPage() {
const overview = adminService.getOverview();
const customers = adminService.getCustomers();
const sendTrendOption = useMemo(
() => createLineOption({
labels: hourlySendTrend.map((item) => item.time),
series: [
{ name: '提交量', data: hourlySendTrend.map((item) => item.sent) },
{ name: '成功量', data: hourlySendTrend.map((item) => item.success) },
],
}),
[],
);
const auditTrendOption = useMemo(
() => createBarOption({
labels: auditTrend.map((item) => item.day),
series: [
{ name: '通过', data: auditTrend.map((item) => item.approved) },
{ name: '驳回', data: auditTrend.map((item) => item.rejected) },
{ name: '待审', data: auditTrend.map((item) => item.pending) },
],
}),
[],
);
const customerGrowthOption = useMemo(
() => createLineOption({
labels: customerGrowth.map((item) => item.month),
series: [
{ name: '活跃客户', data: customerGrowth.map((item) => item.active) },
{ name: '新增客户', data: customerGrowth.map((item) => item.new) },
],
}),
[],
);
const channelShareOption = useMemo(() => createPieOption({ data: channelShare }), []);
return (
<section className="page-stack">
<div className="page-heading">
<div>
<p className="eyebrow"></p>
<h1></h1>
</div>
<Button icon={<BarChart3 size={16} />} variant="ghost"></Button>
</div>
<div className="dashboard-grid">
<div className="surface metric-card">
<span></span>
<strong>{overview.todaySubmissions}</strong>
<small></small>
</div>
<div className="surface metric-card">
<span></span>
<strong>{customers.filter((item) => item.status === 'active').length}</strong>
<small></small>
</div>
<div className="surface metric-card">
<span></span>
<strong>{overview.channelHealth}%</strong>
<small> 24 </small>
</div>
</div>
<div className="chart-grid">
<div className="surface chart-card">
<div className="section-heading">
<div>
<h2></h2>
<p className="muted"> 3 </p>
</div>
<Tag tone="info"></Tag>
</div>
<Chart height={320} option={sendTrendOption} />
</div>
<div className="surface chart-card">
<div className="section-heading">
<div>
<h2></h2>
<p className="muted"></p>
</div>
<Tag tone="accent"></Tag>
</div>
<Chart height={320} option={channelShareOption} />
</div>
</div>
<div className="chart-grid">
<div className="surface chart-card">
<div className="section-heading">
<div>
<h2></h2>
<p className="muted"> 7 </p>
</div>
<Tag tone="warning"></Tag>
</div>
<Chart height={320} option={auditTrendOption} />
</div>
<div className="surface chart-card">
<div className="section-heading">
<div>
<h2></h2>
<p className="muted"></p>
</div>
<Tag tone="success"></Tag>
</div>
<Chart height={320} option={customerGrowthOption} />
</div>
</div>
</section>
);
}