feat: complete cmpp gateway delivery recovery workflows

This commit is contained in:
hectorzhao
2026-07-08 16:30:06 +08:00
parent cc628d0214
commit 8144f08652
60 changed files with 8901 additions and 94 deletions
+40 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react';
import { MessageSquare, Search, Smartphone } from 'lucide-react';
import { adminApi, type SmsMessageRecord } from '@/api/adminApi';
import { adminApi, type SmsMessageRecord, type SmsMessageSegmentAudit } from '@/api/adminApi';
import { Breadcrumb, Button, DateRangeInput, Input, Modal, Select, Tag, type DateRangeValue, type TableColumn, Table } from '@/components/ui';
const statusLabelMap: Record<string, string> = {
@@ -28,6 +28,8 @@ export function AdminSmsRecordsPage() {
const [contentKeyword, setContentKeyword] = useState('');
const [status, setStatus] = useState('all');
const [selectedRecord, setSelectedRecord] = useState<SmsMessageRecord | null>(null);
const [segmentAudits, setSegmentAudits] = useState<SmsMessageSegmentAudit[]>([]);
const [segmentLoading, setSegmentLoading] = useState(false);
const [error, setError] = useState('');
function loadData() {
@@ -43,6 +45,21 @@ export function AdminSmsRecordsPage() {
loadData();
}, []);
useEffect(() => {
if (!selectedRecord) {
setSegmentAudits([]);
return;
}
setSegmentLoading(true);
adminApi.listMessageSegmentAudits({ messageRecordId: selectedRecord.id })
.then((items) => {
setSegmentAudits(items);
setError('');
})
.catch((failure: Error) => setError(failure.message || '分片审计加载失败'))
.finally(() => setSegmentLoading(false));
}, [selectedRecord]);
const filteredRows = useMemo(
() => records.filter((item) => {
const submittedDate = item.queuedAt.slice(0, 10);
@@ -64,6 +81,18 @@ export function AdminSmsRecordsPage() {
{ key: 'actions', title: '操作', width: '120px', align: 'right', render: (record) => <Button onClick={() => setSelectedRecord(record)} size="sm" variant="ghost"></Button> },
];
const segmentColumns: Array<TableColumn<SmsMessageSegmentAudit>> = [
{ key: 'segment', title: '分片', width: '90px', render: (record) => `${record.segmentIndex}/${record.segmentTotal}` },
{ key: 'submitId', title: '提交ID', width: '190px', render: (record) => <strong className="admin-task-id">{record.submitId}</strong> },
{ key: 'channel', title: '通道', width: '150px', render: (record) => record.channel?.name ?? record.channelId ?? '-' },
{ key: 'sequenceId', title: 'Sequence', width: '110px', render: (record) => record.sequenceId ?? '-' },
{ key: 'gatewayMessageId', title: 'MsgId', width: '180px', render: (record) => record.gatewayMessageId ?? '-' },
{ key: 'submitStatus', title: '提交状态', width: '110px', render: (record) => <Tag tone={record.submitStatus === 'accepted' ? 'success' : record.submitStatus === 'queued' ? 'info' : 'danger'}>{record.submitStatus}</Tag> },
{ key: 'receiptStatus', title: '回执状态', width: '110px', render: (record) => record.receiptStatus ? <Tag tone={record.receiptStatus === 'delivered' ? 'success' : record.receiptStatus === 'unknown' ? 'neutral' : 'danger'}>{record.receiptStatus}</Tag> : '-' },
{ key: 'compensation', title: '补偿', width: '120px', render: (record) => record.compensationType ?? '-' },
{ key: 'error', title: '错误', render: (record) => record.errorMessage ?? record.errorCode ?? '-' },
];
function resetFilters() {
setDateRange({});
setPhoneKeyword('');
@@ -125,6 +154,16 @@ export function AdminSmsRecordsPage() {
<p>{statusLabelMap[selectedRecord.status] ?? selectedRecord.status}</p>
<p>{selectedRecord.errorMessage ?? '-'}</p>
</section>
<section>
<h3></h3>
<Table
columns={segmentColumns}
data={segmentAudits}
emptyText={segmentLoading ? '加载中...' : '暂无分片审计'}
pagination={false}
rowKey="id"
/>
</section>
</div>
) : null}
</Modal>