feat: enforce signature-scoped drainage authorization before SMS submission

This commit is contained in:
hectorzhao
2026-09-10 13:29:04 +08:00
parent 5bcdbb2a03
commit 0c3f820cc9
35 changed files with 2769 additions and 791 deletions
+19 -2
View File
@@ -134,6 +134,13 @@ export type SmsMessageRecord = {
categories?: string[];
truncated?: boolean;
} | null;
drainageGate?: {
version: string;
evaluatedAt: string;
reason: string | null;
reasonCode: string | null;
targets: Array<{ category: string; text: string; value: string; materialIds: string[] }>;
} | null;
drainageDetectionVersion?: string | null;
drainageEvaluatedAt?: string | null;
clientSrcId?: string | null;
@@ -331,7 +338,14 @@ export type SystemLogExportResult = {
recordCount: number;
truncated: boolean;
content: string;
filters: { keyword?: string; level?: string; module?: string; range?: string; createdAtFrom?: string; createdAtTo?: string };
filters: {
keyword?: string;
level?: string;
module?: string;
range?: string;
createdAtFrom?: string;
createdAtTo?: string;
};
};
export type DailyReconciliationReport = {
@@ -638,7 +652,10 @@ export type GatewaySubmitException = {
updatedAt: string;
tenant?: Pick<TenantOption, 'id' | 'name' | 'code' | 'status'> | null;
application?: Pick<EnterpriseApplication, 'id' | 'tenantId' | 'name' | 'status'> | null;
channel?: Pick<AdminChannel, 'id' | 'code' | 'name' | 'status' | 'carrier' | 'sendRegion' | 'rateLimitPerSecond'> | null;
channel?: Pick<
AdminChannel,
'id' | 'code' | 'name' | 'status' | 'carrier' | 'sendRegion' | 'rateLimitPerSecond'
> | null;
};
export type GatewaySubmitExceptionResponse = PagedResponse<GatewaySubmitException> & {
@@ -47,6 +47,26 @@ export function SendDetailModal({ record, segmentAudits, segmentLoading, onClose
}
>
<div className="admin-sms-send-detail">
<section aria-label="引流发送资格">
<h3></h3>
{record.drainageGate ? (
<>
<p>
{record.drainageGate.reason ||
(record.drainageGate.targets.length
? '引流信息资格检查通过;发送仍受通道及其他规则限制'
: '未检测到引流信息')}
</p>
{record.drainageGate.targets.map((target, index) => (
<p key={index}>
{target.text} · {target.materialIds.length ? '已匹配审核通过的资料' : '未匹配有效资料'}
</p>
))}
</>
) : (
<p className="muted">{segmentLoading ? '正在加载引流资格校验结果…' : '未执行引流资格校验'}</p>
)}
</section>
<div className="admin-sms-detail-overview">
<div>
<span></span>