feat: complete cmpp gateway delivery recovery workflows
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user