fix: align daily operations statistics
This commit is contained in:
@@ -1,26 +1,18 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { BarChart3 } from 'lucide-react';
|
||||
import { adminApi, type DashboardResponse } from '@/api/adminApi';
|
||||
import { adminApi, type SendQualityResponse } from '@/api/adminApi';
|
||||
import { Breadcrumb, Button, Chart, Input, Tag } from '@/components/ui';
|
||||
import { createBarOption, createPieOption } from '@/theme/chartOptions';
|
||||
|
||||
export function AdminAnalyticsPage() {
|
||||
const [statisticsDate, setStatisticsDate] = useState(() => shanghaiDateKey());
|
||||
const [dashboard, setDashboard] = useState<DashboardResponse | null>(null);
|
||||
const [tenantStats, setTenantStats] = useState<Array<{ tenantId: string | null; _count: { _all: number }; _sum: { amountCents?: number | null } }>>([]);
|
||||
const [channelStats, setChannelStats] = useState<Array<{ channelId: string; channelName: string; total: number }>>([]);
|
||||
const [quality, setQuality] = useState<SendQualityResponse | null>(null);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
function loadData() {
|
||||
Promise.all([
|
||||
adminApi.getDashboard(),
|
||||
adminApi.listStatistics({ groupBy: 'tenantId' }),
|
||||
adminApi.getSendQuality(statisticsDate),
|
||||
])
|
||||
.then(([dashboardData, tenantData, qualityData]) => {
|
||||
setDashboard(dashboardData);
|
||||
setTenantStats((Array.isArray(tenantData) ? tenantData : []) as Array<{ tenantId: string | null; _count: { _all: number }; _sum: { amountCents?: number | null } }>);
|
||||
setChannelStats(qualityData.channels.map((item) => ({ channelId: item.channelId, channelName: item.channelName, total: item.total })));
|
||||
adminApi.getSendQuality(statisticsDate)
|
||||
.then((qualityData) => {
|
||||
setQuality(qualityData);
|
||||
setError('');
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '统计数据加载失败'));
|
||||
@@ -30,14 +22,15 @@ export function AdminAnalyticsPage() {
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const tenantOption = useMemo(() => createBarOption({
|
||||
labels: tenantStats.map((item) => item.tenantId ?? '未绑定企业'),
|
||||
series: [{ name: '发送量', data: tenantStats.map((item) => item._count._all) }],
|
||||
}), [tenantStats]);
|
||||
const applicationOption = useMemo(() => createBarOption({
|
||||
labels: quality?.applications.map((item) => item.applicationName) ?? [],
|
||||
series: [{ name: '发送量', data: quality?.applications.map((item) => item.total) ?? [] }],
|
||||
}), [quality]);
|
||||
|
||||
const channelOption = useMemo(() => createPieOption({
|
||||
data: channelStats.map((item) => ({ name: item.channelName || item.channelId, value: item.total })),
|
||||
}), [channelStats]);
|
||||
data: quality?.channels.map((item) => ({ name: item.channelName || item.channelId, value: item.total })) ?? [],
|
||||
}), [quality]);
|
||||
const effectiveDate = quality?.date ?? statisticsDate;
|
||||
|
||||
return (
|
||||
<section className="page-stack">
|
||||
@@ -60,19 +53,14 @@ export function AdminAnalyticsPage() {
|
||||
|
||||
<div className="dashboard-grid">
|
||||
<div className="surface metric-card">
|
||||
<span>今日发送量</span>
|
||||
<strong>{dashboard?.today.sent.toLocaleString('zh-CN') ?? 0}</strong>
|
||||
<small>真实消息记录</small>
|
||||
<span>{effectiveDate} 发送量</span>
|
||||
<strong>{quality?.summary.total.toLocaleString('zh-CN') ?? 0}</strong>
|
||||
<small>所选日期真实消息记录</small>
|
||||
</div>
|
||||
<div className="surface metric-card">
|
||||
<span>成功率</span>
|
||||
<strong>{dashboard?.today.successRate ?? 0}%</strong>
|
||||
<small>今日已回执</small>
|
||||
</div>
|
||||
<div className="surface metric-card">
|
||||
<span>待审核</span>
|
||||
<strong>{dashboard?.pendingAuditCount ?? 0}</strong>
|
||||
<small>企业/签名/模板/风控</small>
|
||||
<span>{effectiveDate} 成功率</span>
|
||||
<strong>{(quality?.summary.successRate ?? 0).toFixed(1)}%</strong>
|
||||
<small>{quality?.summary.successCount.toLocaleString('zh-CN') ?? 0} 条已送达 / {quality?.summary.total.toLocaleString('zh-CN') ?? 0} 条发送</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,18 +68,18 @@ export function AdminAnalyticsPage() {
|
||||
<div className="surface chart-card">
|
||||
<div className="section-heading">
|
||||
<div>
|
||||
<h2>企业发送排行</h2>
|
||||
<p className="muted">按真实短信消息记录聚合。</p>
|
||||
<h2>企业应用发送排行</h2>
|
||||
<p className="muted">{effectiveDate} 当天按企业应用名称聚合真实短信消息记录。</p>
|
||||
</div>
|
||||
<Tag tone="info">企业</Tag>
|
||||
<Tag tone="info">企业应用</Tag>
|
||||
</div>
|
||||
<Chart height={320} option={tenantOption} />
|
||||
<Chart height={320} option={applicationOption} />
|
||||
</div>
|
||||
<div className="surface chart-card">
|
||||
<div className="section-heading">
|
||||
<div>
|
||||
<h2>通道占比</h2>
|
||||
<p className="muted">{statisticsDate} 当天按真实通道提交及回执聚合。</p>
|
||||
<p className="muted">{effectiveDate} 当天按真实通道提交及回执聚合。</p>
|
||||
</div>
|
||||
<Tag tone="accent">通道</Tag>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user