feat: refine operations UI and transport limits
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user