feat: refine operations UI and transport limits

This commit is contained in:
hectorzhao
2026-08-13 10:42:59 +08:00
parent fb02cbcf39
commit 67fee21616
34 changed files with 314 additions and 188 deletions
+3 -85
View File
@@ -12,12 +12,11 @@ import {
Chart,
Modal,
MoneyText,
Pagination,
Table,
Tag,
type TableColumn,
} from '@/components/ui';
import { adminApi, type DashboardResponse, type SendQualityResponse, type SignatureQualityStat } from '@/api/adminApi';
import { adminApi, type DashboardResponse, type SendQualityResponse } from '@/api/adminApi';
import { createDualAxisBarLineOption, createLineOption } from '@/theme/chartOptions';
import { formatAmount, moneyUnitsToYuan } from '@/utils/currency';
@@ -29,12 +28,6 @@ type EnterpriseSpendRank = {
availableBalance: number;
};
type RankedSignatureQualityStat = SignatureQualityStat & {
rank: number;
};
const SIGNATURE_PAGE_SIZE = 10;
const balanceTone = {
: 'success',
: 'warning',
@@ -55,8 +48,6 @@ export function AdminHome() {
const [quality, setQuality] = useState<SendQualityResponse | null>(null);
const [error, setError] = useState('');
const [selectedEnterprise, setSelectedEnterprise] = useState<EnterpriseSpendRank | null>(null);
const [plainSignaturePage, setPlainSignaturePage] = useState(1);
const [drainageSignaturePage, setDrainageSignaturePage] = useState(1);
useEffect(() => {
Promise.all([adminApi.getDashboard(), adminApi.getSendQuality()])
@@ -146,36 +137,6 @@ export function AdminHome() {
},
];
const signatureColumns: Array<TableColumn<RankedSignatureQualityStat>> = [
{ key: 'rank', title: '排名', width: '72px', render: (record) => record.rank },
{ key: 'signatureName', title: '签名', render: (record) => <div><strong>{record.signatureName}</strong><p className="text-caption">{record.tenantName}</p></div> },
{ key: 'total', title: '发送总数', align: 'right', render: (record) => formatCount(record.total) },
{ key: 'submitFailureCount', title: '提交失败', align: 'right', render: (record) => formatCount(record.submitFailureCount) },
{ key: 'successCount', title: '成功', align: 'right', render: (record) => formatCount(record.successCount) },
{ key: 'unknownCount', title: '未知', align: 'right', render: (record) => formatCount(record.unknownCount) },
{ key: 'failureCount', title: '失败', align: 'right', render: (record) => formatCount(record.failureCount) },
{ key: 'successRate', title: '成功率', align: 'right', render: (record) => `${record.successRate.toFixed(1)}%` },
{ key: 'averageArrivalMs', title: '平均到达', align: 'right', render: (record) => record.averageArrivalMs === null || record.averageArrivalMs === undefined ? '-' : `${(record.averageArrivalMs / 1000).toFixed(1)}` },
];
const plainSignatureQuality = quality?.signatures ?? [];
const drainageSignatureQuality = quality?.drainageSignatures ?? [];
const plainSignatureTotalPages = Math.max(1, Math.ceil(plainSignatureQuality.length / SIGNATURE_PAGE_SIZE));
const drainageSignatureTotalPages = Math.max(1, Math.ceil(drainageSignatureQuality.length / SIGNATURE_PAGE_SIZE));
const pagedPlainSignatureQuality = plainSignatureQuality
.slice((plainSignaturePage - 1) * SIGNATURE_PAGE_SIZE, plainSignaturePage * SIGNATURE_PAGE_SIZE)
.map((item, index) => ({ ...item, rank: (plainSignaturePage - 1) * SIGNATURE_PAGE_SIZE + index + 1 }));
const pagedDrainageSignatureQuality = drainageSignatureQuality
.slice((drainageSignaturePage - 1) * SIGNATURE_PAGE_SIZE, drainageSignaturePage * SIGNATURE_PAGE_SIZE)
.map((item, index) => ({ ...item, rank: (drainageSignaturePage - 1) * SIGNATURE_PAGE_SIZE + index + 1 }));
useEffect(() => {
setPlainSignaturePage((page) => Math.min(page, plainSignatureTotalPages));
}, [plainSignatureTotalPages]);
useEffect(() => {
setDrainageSignaturePage((page) => Math.min(page, drainageSignatureTotalPages));
}, [drainageSignatureTotalPages]);
return (
<section className="page-stack admin-dashboard">
<div className="overview-hero admin-dashboard-hero">
@@ -205,8 +166,8 @@ export function AdminHome() {
<small>delivered / </small>
</div>
<div className="surface metric-card">
<span></span>
<strong><MoneyText>¥{formatCurrency(todaySpend)}</MoneyText></strong>
<span></span>
<strong>¥{formatCurrency(todaySpend)}</strong>
<small></small>
</div>
<div className="surface metric-card">
@@ -230,49 +191,6 @@ export function AdminHome() {
</div>
</div>
<div className="overview-grid admin-signature-rank-grid">
<div className="surface section-stack">
<div className="section-heading">
<div>
<h2></h2>
<p className="muted"></p>
</div>
<Tag tone="info">{plainSignatureQuality.length} </Tag>
</div>
<Table columns={signatureColumns} data={pagedPlainSignatureQuality} emptyText="今日暂无签名发送记录" rowKey="id" />
<Pagination
total={plainSignatureQuality.length}
page={plainSignaturePage}
totalPages={plainSignatureTotalPages}
previousDisabled={plainSignaturePage <= 1}
nextDisabled={plainSignaturePage >= plainSignatureTotalPages}
onPrevious={() => setPlainSignaturePage((page) => Math.max(1, page - 1))}
onNext={() => setPlainSignaturePage((page) => Math.min(plainSignatureTotalPages, page + 1))}
onPageChange={setPlainSignaturePage}
/>
</div>
<div className="surface section-stack">
<div className="section-heading">
<div>
<h2> - </h2>
<p className="muted"></p>
</div>
<Tag tone="accent">{drainageSignatureQuality.length} </Tag>
</div>
<Table columns={signatureColumns} data={pagedDrainageSignatureQuality} emptyText="今日暂无含引流的签名发送记录" rowKey="id" />
<Pagination
total={drainageSignatureQuality.length}
page={drainageSignaturePage}
totalPages={drainageSignatureTotalPages}
previousDisabled={drainageSignaturePage <= 1}
nextDisabled={drainageSignaturePage >= drainageSignatureTotalPages}
onPrevious={() => setDrainageSignaturePage((page) => Math.max(1, page - 1))}
onNext={() => setDrainageSignaturePage((page) => Math.min(drainageSignatureTotalPages, page + 1))}
onPageChange={setDrainageSignaturePage}
/>
</div>
</div>
<div className="surface section-stack">
<div className="section-heading">
<div>