fix: align reporting filters and carrier quality

This commit is contained in:
hectorzhao
2026-07-28 20:55:50 +08:00
parent d8e5319647
commit 95c052e9ea
10 changed files with 172 additions and 52 deletions
+11 -26
View File
@@ -290,7 +290,14 @@ function SignatureQualityDrawer({
item: SignatureChannelQualityItem;
onClose: () => void;
}) {
const carriers = aggregateByCarrier(item.breakdowns);
const carriers = item.carrierOverview.map((carrier) => ({
...carrier,
channelCount: new Set(
item.breakdowns
.filter((entry) => normalizeCarrier(entry.carrier) === normalizeCarrier(carrier.carrier))
.map((entry) => entry.channelId),
).size,
}));
const channels = [...new Map(item.breakdowns.map((entry) => [entry.channelId, entry.channelName])).entries()]
.map(([channelId, channelName]) => ({ channelId, channelName }));
const visibleCarriers = carrierOrder.filter((carrier) => item.breakdowns.some((entry) => normalizeCarrier(entry.carrier) === carrier));
@@ -321,7 +328,7 @@ function SignatureQualityDrawer({
<div className="signature-quality-section__heading">
<div>
<h3></h3>
<p></p>
<p></p>
</div>
</div>
<div className="signature-carrier-grid">
@@ -329,10 +336,10 @@ function SignatureQualityDrawer({
<article className={`signature-carrier-card signature-carrier-card--${normalizeCarrier(carrier.carrier)}`} key={carrier.carrier}>
<div>
<Tag tone={carrierTagTone(carrier.carrier)}>{carrierLabel(carrier.carrier)}</Tag>
<strong>{carrier.total.toLocaleString('zh-CN')} </strong>
<strong>{carrier.businessMessageCount.toLocaleString('zh-CN')} </strong>
</div>
<dl>
<div><dt></dt><dd>{carrier.successRate.toFixed(1)}%</dd></div>
<div><dt></dt><dd>{carrier.finalSuccessRate.toFixed(1)}%</dd></div>
<div><dt></dt><dd>{formatDuration(carrier.averageArrivalMs)}</dd></div>
<div><dt></dt><dd>{carrier.channelCount} </dd></div>
</dl>
@@ -417,28 +424,6 @@ function QualityRate({ value }: { value: number }) {
);
}
function aggregateByCarrier(items: SignatureChannelCarrierQualityStat[]) {
return carrierOrder
.map((carrier) => {
const entries = items.filter((item) => normalizeCarrier(item.carrier) === carrier);
if (entries.length === 0) return null;
const acceptedCount = entries.reduce((sum, item) => sum + item.acceptedCount, 0);
const successCount = entries.reduce((sum, item) => sum + item.successCount, 0);
const arrivalWeight = entries.reduce((sum, item) => (
sum + (item.averageArrivalMs == null ? 0 : item.averageArrivalMs * item.successCount)
), 0);
const arrivalCount = entries.reduce((sum, item) => sum + (item.averageArrivalMs == null ? 0 : item.successCount), 0);
return {
carrier,
total: entries.reduce((sum, item) => sum + item.total, 0),
successRate: acceptedCount === 0 ? 0 : successCount * 100 / acceptedCount,
averageArrivalMs: arrivalCount === 0 ? null : Math.round(arrivalWeight / arrivalCount),
channelCount: new Set(entries.map((item) => item.channelId)).size,
};
})
.filter((item): item is NonNullable<typeof item> => item !== null);
}
function normalizeCarrier(value: string) {
const normalized = value.toLowerCase();
if (['mobile', 'cmcc', '移动'].includes(normalized)) return 'mobile';
+24 -22
View File
@@ -204,31 +204,33 @@ export function AdminReportMaterialsPage() {
{ key: 'files', title: '报备文件', align: 'right', render: (batch) => <div className="table-actions">{batch.exportFiles.map((file) => file.fileObjectId ? <a href={fileDownloadUrl(file.fileObjectId)} key={file.id}><Download size={15} />{file.fileName}{file.rowCount}</a> : null)}</div> },
], []);
const filter = <div className="surface report-material-filter">
const filter = <div className={`surface report-material-filter report-material-filter--${activeTab}`}>
{activeTab === 'pending' ? <Select label="资料类型" onChange={(event) => { setReportType(event.target.value); setPendingPage(1); }} options={[{ label: '全部资料', value: 'all' }, { label: '签名资料', value: 'signature' }, { label: '引流信息', value: 'drainage' }]} value={reportType} /> : null}
<Input label={activeTab === 'pending' ? '企业/应用/签名/站点' : '报备批次号'} onChange={(event) => setKeyword(event.target.value)} placeholder={activeTab === 'pending' ? '搜索待生成资料' : '搜索报备批次号'} value={keyword} />
<DateRangeInput label={activeTab === 'pending' ? '资料变更时间' : '批次生成时间'} onChange={setDateRange} value={dateRange} />
<Button icon={<Search size={16} />} onClick={() => {
if (activeTab === 'pending') {
setPendingPage(1);
void loadPending(1);
} else {
setBatchPage(1);
void loadBatches(1);
}
}}></Button>
<Button onClick={() => {
setKeyword('');
setDateRange({});
if (activeTab === 'pending') {
setReportType('all');
setPendingPage(1);
void loadPending(1, { keyword: '', dateRange: {}, reportType: 'all' });
} else {
setBatchPage(1);
void loadBatches(1, { keyword: '', dateRange: {} });
}
}} variant="ghost"></Button>
<div className="ui-query-actions">
<Button icon={<Search size={16} />} onClick={() => {
if (activeTab === 'pending') {
setPendingPage(1);
void loadPending(1);
} else {
setBatchPage(1);
void loadBatches(1);
}
}}></Button>
<Button onClick={() => {
setKeyword('');
setDateRange({});
if (activeTab === 'pending') {
setReportType('all');
setPendingPage(1);
void loadPending(1, { keyword: '', dateRange: {}, reportType: 'all' });
} else {
setBatchPage(1);
void loadBatches(1, { keyword: '', dateRange: {} });
}
}} variant="ghost"></Button>
</div>
</div>;
return <section className="page-stack report-material-page">