feat(analytics): 管理层指标呈现——首响回复率上墙/客户资产总览/自定义日期/排行五新列

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-07 14:41:08 +08:00
parent feb3b98665
commit 085a9b4fd3
6 changed files with 606 additions and 43 deletions
+29 -4
View File
@@ -4,7 +4,8 @@ import { getJson, requestJson } from './client'
import type { Channel, Page } from './types'
export type { Channel }
export type Scope = 'today' | 'week' | 'month' | 'last30'
// 批2(2026-09-07):'custom'=自定义日期范围,须配合 start/end yyyymmdd
export type Scope = 'today' | 'week' | 'month' | 'last30' | 'custom'
// 看板 v2(2026-09-07):overview 渠道参数支持 'all'=全平台(后端译成
// channel=None);列表页(churn/unreplied)仍是单渠道,沿用 types.ts 的 Channel
export type DashboardChannel = 'all' | Channel
@@ -19,15 +20,35 @@ export interface OverviewCards {
prev_msg_total?: number
msg_total_delta?: number | null
}
// B1 客户资产总览:全库存量快照,不随 scope/channel
export interface CustomerAssets {
total: number
active30: number
silent30_90: number
sleeping90p: number
never: number
wechat: number
whatsapp: number
deleted: number
}
export interface TrendPoint { day: number; msg: number; active_customers: number; call_cnt: number }
export interface AnomalyStaff { user_id: string; yesterday: number; prev7_mean: number; new?: boolean }
export interface Anomaly { total_delta_pct: number; yesterday_total: number; prev7_mean: number; staff: AnomalyStaff[] }
// 员工活跃排行(2026-09-07 管理者反馈补强):active_*=窗内 distinct peer,
// msg_delta 仅周/月且当前/前窗均非 0 才有值
// msg_delta 仅周/月/custom 且当前/前窗均非 0 才有值。
// 批2 五新列:fr_avg_ms/reply_rate(=null 无样本/无串)、first_contact_cnt、
// call_seconds/answer_rate(=null 无通话);deleted/blocked_friends=全库存量
export interface StaffRankingRow {
user_id: string; name: string; unmapped: boolean
msg_total: number; active_friends: number; active_rooms: number
call_cnt: number; msg_delta: number | null
fr_avg_ms: number | null
reply_rate: number | null
first_contact_cnt: number
call_seconds: number
answer_rate: number | null
deleted_friends: number
blocked_friends: number
}
export interface ActionCounts { unreplied_2h: number; churn_real_30d: number; sensitive_pending: number }
// by_channel/trend_by_channel 仅 channel='all' 时后端才返回(可选字段);
@@ -38,6 +59,7 @@ export interface OverviewResp {
channel: Channel | 'all'
days: number[]
cards: OverviewCards
customer_assets: CustomerAssets
trend: TrendPoint[]
anomaly: Anomaly | null
staff_ranking: StaffRankingRow[]
@@ -64,8 +86,11 @@ export interface SensitiveHitRow {
room_id: string | null; ts: number | null; snippet: string | null; disposition: string
}
export const getOverview = (channel: DashboardChannel, scope: Scope) =>
getJson<OverviewResp>('/analytics/overview', { channel, scope })
// scope='custom' 时必须传 start/end(yyyymmdd,后端校验跨度≤366 天)
export const getOverview = (
channel: DashboardChannel, scope: Scope, start?: string, end?: string,
) =>
getJson<OverviewResp>('/analytics/overview', { channel, scope, start, end })
export const getAnalyticsHealth = () => getJson<HealthResp>('/analytics/health')
export const getChurn = (params: Record<string, unknown>) =>
getJson<Page<ChurnRow>>('/analytics/churn', params)