tab.value === kind)?.label}>
{error ? (
{error}
{signatureQuality || activity || unreportedSignatures
? `;仍显示上次成功查询的数据,日期为 ${appliedDate}。`
: ';尚无成功查询的数据。'}
) : null}
{metadata ? (
{metadata.dataSource === 'live' ? '当天实时查询' : metadata.frozen ? '已冻结日报' : '近三日可刷新日报'} ·{' '}
{metadata.reportState === 'missing'
? '报表尚未生成'
: metadata.reportState === 'failed'
? '生成失败,保留上次完整日报'
: metadata.reportState === 'refreshing'
? '正在刷新,显示上次完整日报'
: '查询完成'}
{metadata.provenance === 'backfill-current-source' ? ' · 事后补建' : ''}
{metadata.sourceAsOf ? ` · 数据截止 ${new Date(metadata.sourceAsOf).toLocaleString('zh-CN')}` : ''}
) : null}
{kind === 'quality' ? (
签名通道发送质量
已登记签名
{signatureQuality?.date ?? effectiveDate} 按签名查看业务结果,明细按真实通道提交尝试拆分运营商与通道。
setSignatureKeyword(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Enter') queryStatistics();
}}
placeholder="搜索签名、企业或应用"
value={signatureKeyword}
/>
} onClick={queryStatistics} variant="secondary">
查询
统计说明:
业务短信按消息记录去重;发生补发时会产生多次通道提交,因此“通道提交”可能大于“业务短信”。
=
Math.max(1, Math.ceil((signatureQuality?.total ?? 0) / (signatureQuality?.pageSize ?? pageSize)))
}
onNext={() => changeSignaturePage((signatureQuality?.page ?? 1) + 1)}
onPageChange={changeSignaturePage}
onPrevious={() => changeSignaturePage((signatureQuality?.page ?? 1) - 1)}
page={signatureQuality?.page ?? 1}
previousDisabled={(signatureQuality?.page ?? 1) <= 1}
total={signatureQuality?.total ?? 0}
totalPages={Math.max(
1,
Math.ceil((signatureQuality?.total ?? 0) / (signatureQuality?.pageSize ?? pageSize)),
)}
/>
) : null}
{kind === 'enterprise' ? (
void loadData(page, appliedKeyword, appliedUnreportedKeyword, appliedDate)}
dimensions={retirementDimensions}
items={retirementHeatmap}
title="企业签名活跃度热力图"
/>
) : null}
{kind === 'channel' ? (
void loadData(page, appliedKeyword, appliedUnreportedKeyword, appliedDate)}
dimensions={retirementDimensions}
items={retirementHeatmap}
title="通道签名活跃度热力图"
/>
) : null}
{kind === 'unreported' ? (
loadUnreportedSignatures(page)}
onSearch={queryStatistics}
/>
) : null}
{selectedSignature ? (
setSelectedSignature(null)}
/>
) : null}
);
}
function RetirementHeatmap({
activity,
filters,
onFilterChange,
onSearch,
onPageChange,
pageSize,
onPageSizeChange,
date,
dimensionType,
dimensions,
items,
title,
}: {
pageSize: number;
onPageSizeChange: (pageSize: number) => void;
date: string;
dimensionType: 'enterprise' | 'channel';
dimensions: SignatureRetirementHeatmapDimension[];
items: SignatureActivityItem[];
title: string;
activity: SignatureActivityResponse | null;
filters: { tenantName: string; applicationName: string; signatureName: string; channelName: string };
onFilterChange: (value: typeof filters) => void;
onSearch: () => void;
onPageChange: (page: number) => void;
}) {
const visible = items.filter((item) => item.dimensionType === dimensionType);
const dates = previousDateKeys(date, 30);
const cellMap = new Map(
visible.map((item) => [
`${item.signatureId}:${item.channelId ?? ''}:${item.carrier}:${item.activityDate.slice(0, 10)}`,
item,
]),
);
const rows = dimensions.map((item) => ({
...item,
key: `${item.signatureId}:${item.channelId ?? ''}:${item.carrier}`,
approvedAt: item.approvedAt?.slice(0, 10) ?? '',
total: (item as SignatureRetirementHeatmapDimension & { total: number }).total ?? 0,
}));
const totalPages = Math.max(1, Math.ceil((activity?.total ?? 0) / pageSize));
const currentPage = activity?.page ?? 1;
const pagedRows = rows;
const setPage = onPageChange;
const coverage = new Map(activity?.coverage.map((day) => [day.date, day]));
return (
{title}
数字为真实受理业务短信数;零提交为灰色,非零按现有六档成功率色阶展示。
{(
[
['tenantName', '企业'],
['applicationName', '企业应用'],
['signatureName', '签名'],
...(dimensionType === 'channel' ? [['channelName', '通道']] : []),
] as Array<[keyof typeof filters, string]>
).map(([key, label]) => (
onFilterChange({ ...filters, [key]: event.target.value })}
/>
))}
}>
查询
所选日之前30天
{activity && !activity.complete ? (
部分日期报表尚未生成,合计仅包含已发布日期,不代表完整30日数据。
) : null}
{rows.length ? (
<>
| 签名维度 |
30日合计 |
{dates.map((dateKey) => (
{dateKey.slice(5)} |
))}
{pagedRows.map((row) => (
|
{row.signatureName}
{row.channelName ? {row.channelName} : null}
|
{row.total.toLocaleString('zh-CN')} |
{dates.map((dateKey) => {
const item = cellMap.get(`${row.key}:${dateKey}`);
const beforeApproval = Boolean(coverage.get(dateKey)?.generationId && !item);
const successRate = item?.acceptedBusinessCount
? (item.deliveredBusinessCount / item.acceptedBusinessCount) * 100
: 0;
const className = beforeApproval
? 'is-inapplicable'
: !item
? ''
: item.acceptedBusinessCount === 0
? 'is-zero'
: `is-rate-${successRateTone(successRate)}`;
const titleText = beforeApproval
? '当日报备维度不适用'
: item
? `提交条数:${item.submittedAttempts} 条\n上游接受条数:${item.acceptedBusinessCount} 条\n发送成功条数:${item.deliveredBusinessCount} 条\n发送成功率:${successRate.toFixed(1)}%\n数据来源:${coverage.get(dateKey)?.frozen ? '冻结日报' : '可刷新日报'}`
: '当日报表尚未生成';
return (
{beforeApproval ? 'N/A' : item ? item.acceptedBusinessCount : '—'}
|
);
})}
))}
>
) : (
{Object.values(filters).some((value) => value.trim())
? '没有匹配企业、企业应用或签名的热力图维度。'
: '暂无已确认到运营商的报备事实,尚未形成检测热力图。'}
)}
= totalPages}
onNext={() => setPage(currentPage + 1)}
onPageChange={setPage}
onPrevious={() => setPage(currentPage - 1)}
page={currentPage}
previousDisabled={currentPage <= 1}
total={activity?.total ?? 0}
totalPages={totalPages}
/>
);
}
function UnreportedSignaturesCard({
pageSize,
onPageSizeChange,
data,
keyword,
loading,
onKeywordChange,
onPageChange,
onSearch,
}: {
pageSize: number;
onPageSizeChange: (pageSize: number) => void;
data: (PagedResult