fix: reconcile caller aggregates and strengthen evidence handling
This commit is contained in:
@@ -27,6 +27,7 @@ export function CallerAnalyticsPage() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const q = { ...filters, onlyAlerts: String(filters.onlyAlerts) };
|
||||
if (q.minutes !== 'custom') { delete q.from; delete q.to; }
|
||||
if (q.minutes === 'today') { const now = new Date(); q.from = new Date(now.toLocaleDateString('en-CA', { timeZone: 'Asia/Shanghai' }) + 'T00:00:00+08:00').toISOString(); delete q.minutes; }
|
||||
if (q.minutes === 'custom') { q.from = new Date(q.from).toISOString(); q.to = new Date(q.to).toISOString(); delete q.minutes; }
|
||||
const result = await api.callerAnalytics(q, { signal: controller.signal });
|
||||
@@ -43,7 +44,7 @@ export function CallerAnalyticsPage() {
|
||||
.then(r => { setDetail(r); setDetailError(''); }).catch(e => { if (!c.signal.aborted) setDetailError(explainApiError(e)); });
|
||||
return () => c.abort();
|
||||
}, [target, data, filters, detailSkip]);
|
||||
const change = (key, value) => setDraft(d => ({ ...d, [key]: value, ...(key === 'view' && value === 'original' ? { vendorGatewayId: '' } : {}) }));
|
||||
const change = (key, value) => setDraft(d => ({ ...d, [key]: value, ...(key === 'view' && value === 'original' ? { vendorGatewayId: '' } : {}), ...(key === 'customerId' ? {customerGatewayId:''} : {}) }));
|
||||
const names = Object.fromEntries(options.customers.map(c => [c.id, c.name]));
|
||||
const gatewayNames = Object.fromEntries(options.vendorGateways.map(c => [c.id, c.name]));
|
||||
const select = (label, key, choices) => <Field label={label}><Select value={draft[key]} onChange={e => change(key, e.target.value)}><option value="">全部</option>{choices.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}</Select></Field>;
|
||||
@@ -75,7 +76,7 @@ export function CallerAnalyticsPage() {
|
||||
</form></Panel>
|
||||
<section className="metric-grid cra-metrics">{[...countColumns, ...rateColumns].map(c => <div key={c.key} className="metric-card"><span>{c.label}</span><strong>{metrics ? c.render ? c.render(metrics) : metrics[c.key] : '—'}</strong></div>)}</section>
|
||||
<p className="muted-text" role="status">{data ? `${formatDateTime(data.from)} — ${formatDateTime(data.to)} · ${data.qualityStatus === 'LIVE' ? '采集运行中' : '数据滞后或不完整'} · 待接通 ${metrics.pendingCalls} · 已结束未接通 ${metrics.failedCalls} · 未知 ${metrics.unknownCalls} · 更新于 ${formatDateTime(data.asOf)}` : '正在读取真实统计数据…'}</p>
|
||||
{data ? <Alert title="口径与数据范围" tone={data.qualityStatus === 'LIVE' ? 'info' : 'warning'}>{data.historyNotice} {data.summaryScope}。183 不代表实际振铃;未接通数含待接通,进行中指标为暂定值。</Alert> : null}
|
||||
{data ? <Alert title="口径与数据范围" tone={data.qualityStatus === 'LIVE' ? 'info' : 'warning'}>{data.historyNotice} {data.summaryScope}。183 不代表实际振铃;未接通数含待接通,进行中指标为暂定值。采集运行状态不代表窗口数据完整性已核验,端到端延迟尚未测定。</Alert> : null}
|
||||
<Panel title="分钟趋势" aside={<span className="muted-text">灰:呼叫 / 蓝:接通 / 绿:应答</span>}>
|
||||
<div className="cra-chart" aria-label="分钟呼叫接通应答趋势">{timeline.map((r,i) => <div key={r.time ?? i} className="cra-chart-column" title={`${formatDateTime(Number(r.time))} 呼叫${r.totalCalls} 接通${r.connectedCalls} 应答${r.answeredCalls}`}><div className="cra-bars"><span style={{height:`${r.totalCalls/max*100}%`}} /><span style={{height:`${r.connectedCalls/max*100}%`}} /><span style={{height:`${r.answeredCalls/max*100}%`}} /></div><small>{new Date(Number(r.time)).toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'})}</small></div>)}</div>
|
||||
{!timeline.length ? <p className="muted-text">当前窗口暂无已采集呼叫</p> : <details><summary>查看趋势数值与三个率</summary><SimpleTable rows={timeline.map((r,i) => ({ ...r, id:i, minute:formatDateTime(Number(r.time)) }))} columns={[{key:'minute',label:'分钟'},...countColumns,...rateColumns]} /></details>}
|
||||
|
||||
Reference in New Issue
Block a user