fix: harden admin and CMPP delivery workflows
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { AlertTriangle, BarChart3, CheckCircle2, Eye, RefreshCw, Search, TimerReset } from 'lucide-react';
|
||||
import { adminApi, type DownstreamDeliveryDashboard, type DownstreamDeliveryRecord, type EnterpriseApplication } from '@/api/adminApi';
|
||||
import { Breadcrumb, Button, Input, Modal, Pagination, Select, Tag } from '@/components/ui';
|
||||
import { Breadcrumb, Button, DateRangeInput, Input, Modal, Pagination, Select, Tag, type DateRangeValue } from '@/components/ui';
|
||||
import { formatDateTime } from '@/utils/dateTime';
|
||||
|
||||
const statusTone: Record<string, 'neutral' | 'info' | 'success' | 'warning' | 'danger'> = {
|
||||
@@ -14,7 +14,6 @@ const statusTone: Record<string, 'neutral' | 'info' | 'success' | 'warning' | 'd
|
||||
};
|
||||
|
||||
const statusLabel: Record<string, string> = {
|
||||
pending: '待首次投递',
|
||||
awaiting_ack: '等待客户端确认',
|
||||
delivered: '客户端已确认',
|
||||
failed: '投递失败',
|
||||
@@ -22,6 +21,13 @@ const statusLabel: Record<string, string> = {
|
||||
rejected: '客户端拒绝',
|
||||
};
|
||||
|
||||
function deliveryStatusLabel(record: DownstreamDeliveryRecord) {
|
||||
if (record.status !== 'pending') return statusLabel[record.status] ?? record.status;
|
||||
if (record.manualRetryCount > 0) return '人工重投排队中';
|
||||
if (record.retryCount > 0) return '等待自动重试';
|
||||
return '待首次投递';
|
||||
}
|
||||
|
||||
const deliveryTypeLabel: Record<string, string> = {
|
||||
receipt: '状态回执',
|
||||
uplink: '上行短信',
|
||||
@@ -43,9 +49,11 @@ function DeliveryDetailModal({ record, onClose }: { record: DownstreamDeliveryRe
|
||||
<div><span>企业</span><strong>{record.tenant?.name ?? record.tenantId}</strong></div>
|
||||
<div><span>应用</span><strong>{record.application?.name ?? record.applicationId}</strong></div>
|
||||
<div><span>投递类型</span><strong>{deliveryTypeLabel[record.deliveryType] ?? record.deliveryType}</strong></div>
|
||||
<div><span>当前状态</span><strong>{statusLabel[record.status] ?? record.status}</strong></div>
|
||||
<div><span>当前状态</span><strong>{deliveryStatusLabel(record)}</strong></div>
|
||||
<div><span>消息 ID</span><strong>{record.messageId ?? '-'}</strong></div>
|
||||
<div><span>重试次数</span><strong>{record.retryCount}</strong></div>
|
||||
<div><span>自动重试次数</span><strong>{record.retryCount}</strong></div>
|
||||
<div><span>人工重投次数</span><strong>{record.manualRetryCount}</strong></div>
|
||||
<div><span>最近人工重投</span><strong>{record.lastRetriedAt ? formatDateTime(record.lastRetriedAt) : '-'}</strong></div>
|
||||
<div><span>下次重试</span><strong>{record.nextRetryAt ?? '-'}</strong></div>
|
||||
<div><span>自动重试</span><strong>{record.retryEnabled ? '开启' : '关闭'}</strong></div>
|
||||
<div><span>写出时间</span><strong>{record.sentAt ?? '-'}</strong></div>
|
||||
@@ -80,6 +88,7 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
const [error, setError] = useState('');
|
||||
const [detail, setDetail] = useState<DownstreamDeliveryRecord | null>(null);
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
||||
const [dateRange, setDateRange] = useState<DateRangeValue>({});
|
||||
|
||||
const loadData = useCallback(() => {
|
||||
setLoading(true);
|
||||
@@ -87,6 +96,8 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
adminApi.getDownstreamDeliveryDashboard({
|
||||
applicationId,
|
||||
deliveryType,
|
||||
createdAtFrom: dateRange.start,
|
||||
createdAtTo: dateRange.end,
|
||||
}),
|
||||
adminApi.listDownstreamDeliveries({
|
||||
keyword,
|
||||
@@ -95,6 +106,8 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
applicationId,
|
||||
page,
|
||||
pageSize,
|
||||
createdAtFrom: dateRange.start,
|
||||
createdAtTo: dateRange.end,
|
||||
}),
|
||||
adminApi.listEnterpriseApplications(),
|
||||
])
|
||||
@@ -108,7 +121,7 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '下游投递记录加载失败'))
|
||||
.finally(() => setLoading(false));
|
||||
}, [applicationId, deliveryType, keyword, page, pageSize, status]);
|
||||
}, [applicationId, dateRange.end, dateRange.start, deliveryType, keyword, page, pageSize, status]);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
@@ -182,6 +195,7 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
|
||||
<div className="surface admin-task-filter">
|
||||
<Input label="消息ID / 账号 / 手机号 / 错误" onChange={(event) => setKeyword(event.target.value)} placeholder="请输入关键字" value={keyword} />
|
||||
<DateRangeInput label="创建日期" onChange={(value) => { setDateRange(value); setPage(1); }} value={dateRange} />
|
||||
<Select
|
||||
label="状态"
|
||||
options={[
|
||||
@@ -232,6 +246,7 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
setStatus('all');
|
||||
setDeliveryType('all');
|
||||
setApplicationId('all');
|
||||
setDateRange({});
|
||||
setPage(1);
|
||||
}}
|
||||
variant="ghost"
|
||||
@@ -379,11 +394,11 @@ export function AdminDownstreamDeliveriesPage() {
|
||||
<strong>{record.messageId ?? '-'}</strong>
|
||||
</div>
|
||||
<div role="cell">
|
||||
<Tag tone={statusTone[record.status] ?? 'info'}>{statusLabel[record.status] ?? record.status}</Tag>
|
||||
<Tag tone={statusTone[record.status] ?? 'info'}>{deliveryStatusLabel(record)}</Tag>
|
||||
</div>
|
||||
<div className="downstream-delivery-list__retry" role="cell">
|
||||
<strong>{record.retryCount}</strong>
|
||||
<span>次</span>
|
||||
<span>自动 / {record.manualRetryCount} 人工</span>
|
||||
</div>
|
||||
<div className={`downstream-delivery-list__error${record.lastError ? '' : ' is-empty'}`} role="cell" title={record.lastError ?? undefined}>
|
||||
{record.lastError ?? '无'}
|
||||
|
||||
Reference in New Issue
Block a user