import { useEffect, useMemo, useState } from 'react'; import { BadgeCheck, BellRing, FileText, PenLine, Plus, ReceiptText, Send, WalletCards, } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { Button, Chart, Table, Tag, type TableColumn } from '@/components/ui'; import { clientApi, type DashboardResponse } from '@/api/adminApi'; import { createLineOption, createPieOption } from '@/theme/chartOptions'; import { formatDateTime } from '@/utils/dateTime'; import { formatAmount, formatCents } from '@/utils/currency'; type RecentTaskRow = { id: string; taskNo: string; scene: string; count: number; channel: string; createdAt: string; status: string; }; const columns: Array> = [ { key: 'taskNo', title: '批次编号', render: (record) => record.taskNo }, { key: 'scene', title: '发送场景', render: (record) => record.scene }, { key: 'count', title: '发送量', render: (record) => `${record.count.toLocaleString('zh-CN')} 条` }, { key: 'channel', title: '通道', render: (record) => record.channel }, { key: 'createdAt', title: '创建时间', render: (record) => record.createdAt }, { key: 'status', title: '状态', render: (record) => {record.status} }, ]; export function ClientHome() { const navigate = useNavigate(); const [dashboard, setDashboard] = useState(null); const [error, setError] = useState(''); useEffect(() => { clientApi.getDashboard() .then(setDashboard) .catch((err) => { setError(err instanceof Error ? err.message : '客户端工作台加载失败'); setDashboard(null); }); }, []); const account = dashboard?.accounts[0]; const availableBalance = ((account?.balanceCents ?? 0) + (account?.creditCents ?? 0)) / 100; const todaySpend = (dashboard?.today.spendCents ?? 0) / 100; const todayRefund = Math.abs((dashboard?.transactions._sum.amountCents ?? 0) < 0 ? 0 : dashboard?.transactions._sum.amountCents ?? 0) / 100; const balanceBaseline = Math.max(availableBalance + todaySpend - todayRefund, availableBalance, 1); const balancePercent = Math.min(100, Math.round((availableBalance / balanceBaseline) * 100)); const recentMessages = useMemo(() => (dashboard?.recentTasks ?? []).map((task) => ({ id: String(task.id ?? task.taskNo), taskNo: String(task.taskNo ?? task.id), scene: String(task.category ?? task.content ?? '短信发送'), count: Number(task.phoneTotal ?? task.progressTotal ?? 0), channel: Array.isArray(task.messages) && task.messages[0]?.channel?.name ? String(task.messages[0].channel.name) : '待路由', createdAt: formatDateTime(task.createdAt ? String(task.createdAt) : null), status: String(task.status ?? 'unknown'), })), [dashboard]); const latestRecharge = dashboard?.recentRecharges[0]; const sendTrendOption = useMemo( () => createLineOption({ labels: ['今日'], series: [ { name: '提交量', data: [dashboard?.today.sent ?? 0] }, { name: '成功量', data: [dashboard?.today.delivered ?? 0] }, ], }), [dashboard], ); const channelShareOption = useMemo(() => createPieOption({ data: (dashboard?.gatewayConnections ?? []).map((item) => ({ name: item.status, value: item._sum.currentConnections ?? item._count._all, })), }), [dashboard]); return (

客户端概览

短信服务工作台

查看账户余额、审核进度、发送趋势和常用业务入口。

账户剩余余额 ¥{formatAmount(availableBalance)} 今日消费 ¥{formatAmount(todaySpend)}
今日发送 {(dashboard?.today.sent ?? 0).toLocaleString('zh-CN')} 成功率 {dashboard?.today.successRate ?? 0}%
今日返还金额 ¥{formatAmount(todayRefund)} 异常回执与退费返还
{error ?
{error}
: null}

快捷操作

覆盖概览页常用入口。

账户状态

企业认证与资源用量。

{account?.status ?? '未知'}
企业主体 {account?.tenant?.name ?? account?.tenantId ?? '当前租户'}
默认签名 由发送资源 API 管理
最近充值 {latestRecharge ? `¥${formatCents(latestRecharge.amountCents)}` : '暂无充值'}
余额水位 {balancePercent}%
模板状态 {dashboard?.pendingAuditCount ?? 0} 待处理 点击进入模板明细
签名状态 真实 API 点击进入签名明细
服务提醒 通道运行正常 备用通道有排队批次,请关注发送详情。

今日发送趋势

按 3 小时聚合提交量和成功量。

运营商占比

按今日提交量估算。

最近发送批次

跟踪发送状态、通道和创建时间。

); }