fix: align signature review and admin operations

This commit is contained in:
hectorzhao
2026-07-27 22:07:51 +08:00
parent 9891ffee23
commit df70b336a0
22 changed files with 326 additions and 57 deletions
+5 -1
View File
@@ -332,6 +332,8 @@ function ChannelFormModal({
<Input
hint={modal.mode === 'edit' ? '已配置的密码不会回显;留空保持不变,填写新密码才更新。' : undefined}
label="网关密码"
autoComplete="new-password"
name="cmpp-gateway-password"
onChange={(event) => setPassword(event.target.value)}
placeholder={modal.mode === 'edit' ? '留空不修改' : '请输入网关密码'}
required={modal.mode === 'create'}
@@ -339,7 +341,7 @@ function ChannelFormModal({
value={password}
/>
<div className="sms-channel-inline-field">
<Input label="* 接入号" onChange={(event) => setAccessNo(event.target.value)} placeholder="请输入通道接入号" value={accessNo} />
<Input autoComplete="off" label="* 接入号" name="cmpp-access-number" onChange={(event) => setAccessNo(event.target.value)} placeholder="请输入通道接入号" value={accessNo} />
<Input label="扩展位数" max="20" min="0" onChange={(event) => setExtensionDigits(event.target.value)} type="number" value={extensionDigits} />
</div>
<Input label="* 通道流速" max="2000" min="1" onChange={(event) => setFlowLimit(event.target.value)} suffix="条/秒" type="number" value={flowLimit} />
@@ -446,7 +448,9 @@ function SmsTestModal({
<strong>{content.length} <i /> {billingCount} </strong>
</div>
<Input
autoComplete="off"
label="接入号(选填)"
name="channel-test-access-number"
onChange={(event) => setAccessNo(event.target.value)}
placeholder="请输入接入号"
value={accessNo}
+5 -6
View File
@@ -70,19 +70,17 @@ export function AdminHome() {
}, []);
const enterpriseSpendRanks = useMemo<EnterpriseSpendRank[]>(() => {
return (dashboard?.accounts ?? []).map((account) => {
const todaySpend = Math.abs(dashboard?.recentRecharges
.filter((item) => item.tenantId === account.tenantId)
.reduce((sum, item) => sum + item.amountCents, 0) ?? 0) / 10_000;
return (dashboard?.enterpriseSpendRanks ?? []).map((account) => {
const todaySpend = moneyUnitsToYuan(account.todaySpendCents);
const availableBalance = moneyUnitsToYuan(account.balanceCents + account.creditCents);
return {
id: account.tenantId,
enterprise: account.tenant?.name ?? account.tenantId,
enterprise: account.tenantName,
todaySpend,
availableBalance,
balanceStatus: (availableBalance <= 0 ? '欠费' : availableBalance < 100 ? '紧张' : '充足') as EnterpriseSpendRank['balanceStatus'],
};
}).sort((left, right) => right.todaySpend - left.todaySpend);
});
}, [dashboard]);
const totalSend = dashboard?.today.sent ?? 0;
@@ -144,6 +142,7 @@ export function AdminHome() {
{ 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) },
+1 -1
View File
@@ -134,7 +134,7 @@ export function AdminRiskRulesPage() {
return (
<section className="page-stack">
<div className="page-heading">
<div><Breadcrumb items={['风控管理', '风控规则']} /><h1></h1><p></p></div>
<div><Breadcrumb items={['审核中心', '风控规则']} /><h1></h1><p></p></div>
<div className="page-heading__actions">
<Button icon={<RefreshCw size={16} />} onClick={load} variant="ghost"></Button>
<Button icon={<Plus size={16} />} onClick={() => setEditor(editorFromRule())}></Button>
+17 -2
View File
@@ -44,6 +44,7 @@ const carrierLabelMap: Record<string, string> = {
type RouteRow = {
id: string;
channel: string;
channelGroup?: string | null;
sentAt?: string | null;
receiptAt?: string | null;
receiptCode?: string | null;
@@ -124,6 +125,7 @@ function getCarrierLabel(carrier?: string | null) {
function buildRouteRows(record: SmsMessageRecord, segmentAudits: SmsMessageSegmentAudit[]): RouteRow[] {
if (segmentAudits.length > 0) {
const submitById = new Map((record.submitRecords ?? []).map((submit) => [submit.submitId, submit]));
const attempts = new Map<string, SmsMessageSegmentAudit[]>();
segmentAudits.forEach((segment) => {
const current = attempts.get(segment.submitId) ?? [];
@@ -143,6 +145,7 @@ function buildRouteRows(record: SmsMessageRecord, segmentAudits: SmsMessageSegme
channel: ordered.find((segment) => segment.channel?.name)?.channel?.name
?? ordered.find((segment) => segment.channelId)?.channelId
?? '-',
channelGroup: submitById.get(submitId)?.channelGroupName ?? submitById.get(submitId)?.channelGroup?.name,
sentAt: sentTimes.sort()[0],
receiptAt: receiptTimes.sort()[receiptTimes.length - 1],
receiptCode: receiptCodes.join(' / ') || undefined,
@@ -163,6 +166,7 @@ function buildRouteRows(record: SmsMessageRecord, segmentAudits: SmsMessageSegme
return {
id: submit.id || String(index + 1),
channel: submit.channel?.name ?? record.channel?.name ?? submit.channelId ?? '-',
channelGroup: submit.channelGroupName ?? submit.channelGroup?.name,
sentAt: submit.submittedAt ?? submit.createdAt,
receiptAt: receipt?.deliveredAt,
receiptCode: receipt?.rawStatus,
@@ -237,6 +241,11 @@ function SendDetailModal({
onClose: () => void;
}) {
const routeRows = buildRouteRows(record, segmentAudits);
const channelGroupNames = Array.from(new Set(routeRows.map((route) => route.channelGroup).filter(Boolean)));
const orderedSegmentAudits = [...segmentAudits].sort((left, right) => {
const timeDiff = new Date(left.createdAt).getTime() - new Date(right.createdAt).getTime();
return timeDiff || left.segmentIndex - right.segmentIndex || left.id.localeCompare(right.id);
});
const sentAccessNumber = `${record.channel?.srcId ?? ''}${record.applicationExtension ?? ''}`;
const displayStatus = getRecordStatus(record);
const receiptNotice = getReceiptNotice(record);
@@ -274,6 +283,10 @@ function SendDetailModal({
<span></span>
<strong>{record.province ?? '-'} / {getCarrierLabel(record.carrier)}</strong>
</div>
<div>
<span></span>
<strong>{channelGroupNames.join(' / ') || '-'}</strong>
</div>
<div>
<span></span>
<strong>{record.clientSrcId || '-'}</strong>
@@ -302,6 +315,7 @@ function SendDetailModal({
<span>{index + 1}</span>
<div>
<strong>{route.channel}</strong>
<p className="muted">{route.channelGroup ?? '-'}</p>
<dl>
<div>
<dt></dt>
@@ -334,7 +348,7 @@ function SendDetailModal({
<div><span></span><strong>{record.submitStatus ?? '-'}</strong></div>
<div><span></span><strong>{record.receiptStatus ?? '-'}</strong></div>
</div>
{['failed', 'rejected'].includes(record.status) || record.errorMessage || record.errorCode ? (
{['submit_failed', 'failed', 'rejected'].includes(displayStatus) ? (
<div className="admin-sms-detail-failure" role="alert">
<AlertTriangle size={20} />
<div><span></span><strong>{record.errorMessage ?? record.errorCode ?? '未返回明确失败原因'}</strong></div>
@@ -348,7 +362,7 @@ function SendDetailModal({
<div className="ui-table__empty"></div>
) : (
<div className="admin-sms-segment-list">
{segmentAudits.map((segment) => (
{orderedSegmentAudits.map((segment) => (
<article className="admin-sms-segment-card" key={segment.id}>
<header>
<strong> {segment.segmentIndex}/{segment.segmentTotal}</strong>
@@ -363,6 +377,7 @@ function SendDetailModal({
<div><dt> ID</dt><dd>{segment.submitId}</dd></div>
<div><dt> MsgId</dt><dd>{segment.gatewayMessageId ?? '-'}</dd></div>
<div><dt></dt><dd>{segment.compensationType ?? '-'}</dd></div>
<div><dt></dt><dd>{getTime(segment.createdAt)}</dd></div>
<div><dt></dt><dd>{segment.errorMessage ?? segment.errorCode ?? '-'}</dd></div>
</dl>
</article>