import { useEffect, useMemo, useState } from 'react'; import { BarChart3, DollarSign, FileCheck2, RadioTower, ShieldCheck, Users, } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { Breadcrumb, Button, Chart, Modal, Table, Tag, type TableColumn, } from '@/components/ui'; import { adminApi, type DashboardResponse } from '@/api/adminApi'; import { createBarOption, createLineOption } from '@/theme/chartOptions'; type EnterpriseSpendRank = { id: string; enterprise: string; todaySpend: number; balanceStatus: '充足' | '紧张' | '欠费'; availableBalance: number; }; const balanceTone = { 充足: 'success', 紧张: 'warning', 欠费: 'danger', } as const; function formatCurrency(value: number) { return value.toLocaleString('zh-CN', { minimumFractionDigits: 3, maximumFractionDigits: 3, }); } function formatCount(value: number) { return value.toLocaleString('zh-CN'); } export function AdminHome() { const navigate = useNavigate(); const [dashboard, setDashboard] = useState(null); const [error, setError] = useState(''); const [selectedEnterprise, setSelectedEnterprise] = useState(null); const [channels, setChannels] = useState>([]); useEffect(() => { Promise.all([adminApi.getDashboard(), adminApi.listChannels()]) .then(([nextDashboard, nextChannels]) => { setDashboard(nextDashboard); setChannels(nextChannels); }) .catch((err) => { setError(err instanceof Error ? err.message : '运营看板加载失败'); setDashboard(null); }); }, []); const enterpriseSpendRanks = useMemo(() => { return (dashboard?.accounts ?? []).map((account) => { const todaySpend = Math.abs(dashboard?.recentRecharges .filter((item) => item.tenantId === account.tenantId) .reduce((sum, item) => sum + item.amountCents, 0) ?? 0) / 100; const availableBalance = (account.balanceCents + account.creditCents) / 100; return { id: account.tenantId, enterprise: account.tenant?.name ?? account.tenantId, todaySpend, availableBalance, balanceStatus: (availableBalance <= 0 ? '欠费' : availableBalance < 100 ? '紧张' : '充足') as EnterpriseSpendRank['balanceStatus'], }; }).sort((left, right) => right.todaySpend - left.todaySpend); }, [dashboard]); const totalSend = dashboard?.today.sent ?? 0; const averageSuccessRate = dashboard?.today.successRate ?? 0; const todaySpend = (dashboard?.today.spendCents ?? 0) / 100; const activeConnectionCount = dashboard?.gatewayConnections.reduce((sum, item) => sum + (item._sum.currentConnections ?? 0), 0) ?? 0; const downstreamAlertCount = dashboard?.downstreamDeliverySummary?.alertCount ?? 0; const pendingAudits = dashboard?.pendingAudits ?? { enterpriseCertifications: 0, smsAudits: 0, templates: 0, signatures: 0, total: 0 }; const sendTrendOption = useMemo( () => createLineOption({ labels: ['今日'], series: [ { name: '提交量', data: [dashboard?.today.sent ?? 0] }, { name: '成功量', data: [dashboard?.today.delivered ?? 0] }, ], }), [dashboard], ); const auditTrendOption = useMemo( () => createBarOption({ labels: ['企业认证', '短信审核', '模板', '签名'], series: [ { name: '待审', data: [pendingAudits.enterpriseCertifications, pendingAudits.smsAudits, pendingAudits.templates, pendingAudits.signatures] }, ], }), [pendingAudits], ); const enterpriseColumns: Array> = [ { key: 'rank', title: '排名', width: '72px', render: (_record, index) => index + 1 }, { key: 'enterprise', title: '企业名称', render: (record) => (
{record.enterprise}

{record.id}

), }, { key: 'todaySpend', title: '今日消费(元)', align: 'right', render: (record) => `¥${formatCurrency(record.todaySpend)}` }, { key: 'availableBalance', title: '可用余额', align: 'right', render: (record) => formatCount(record.availableBalance) }, { key: 'balanceStatus', title: '余额状态', render: (record) => {record.balanceStatus} }, { key: 'actions', title: '操作', align: 'right', render: (record) => ( ), }, ]; const channelColumns: Array> = [ { key: 'name', title: '通道名称', render: (record) => {record.name} }, { key: 'status', title: '状态', render: (record) => {record.status} }, { key: 'rateLimitPerSecond', title: '限速', align: 'right', render: (record) => `${record.rateLimitPerSecond}/s` }, ]; return (

按业务口径查看平台发送、签名、消费、审核和通道运行情况。

今日发送总量 {formatCount(totalSend)} 条 来自真实短信记录聚合
总体成功率 {averageSuccessRate.toFixed(1)}% delivered / 今日总量
今日消费 ¥{formatCurrency(todaySpend)} 来自今日消息金额聚合
通道在线连接 {activeConnectionCount} Gateway 连接状态回写
{error ?
{error}
: null}

今日发送趋势

按真实后端今日聚合展示提交量和成功量。

审核处理趋势

待审核数量来自真实审核聚合。

今日企业消费排行

来自真实账户、充值和消息金额聚合。

通道运行

核心通道成功率和延迟。

运营状态

当日关键流程状态汇总。

平均等待 {dashboard?.taskCount ?? 0} 任务 真实批量任务总数。
平台健康度 {activeConnectionCount} 在线连接数。
下游投递告警 {downstreamAlertCount} 条 积压过久或近期失败。
)} onClose={() => setSelectedEnterprise(null)} open={Boolean(selectedEnterprise)} title={(

企业消费详情

{selectedEnterprise?.id}

)} > {selectedEnterprise ? (
企业名称 {selectedEnterprise.enterprise}
企业ID {selectedEnterprise.id}
余额状态 {selectedEnterprise.balanceStatus}
今日消费 ¥{formatCurrency(selectedEnterprise.todaySpend)}
可用余额 {formatCount(selectedEnterprise.availableBalance)}
) : null}
); }