feat(management): 驾驶舱KPI环比(prev_kpis+delta)+异常卡带员工名跳详情+列表进详情带筛选
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
page_size>100)、404(employees/{ghost}、drilldown 员工不存在);
|
||||
- dashboard 各段齐全与关键数值(kpis/communication_trend/service_trend/
|
||||
lifecycle/dimension_summary/anomalies/action_summary/data_as_of/
|
||||
metric_version);
|
||||
metric_version);批次D 补:prev_kpis 环比块+msg_delta(含前窗零数据
|
||||
→None)与 anomalies employee_name enrich(详情端点不带);
|
||||
- employees:默认分页 20/total/critical 优先默认排序/channel=wechat 时
|
||||
whatsapp-only 员工消失/keyword/status/min_days 不足→insufficient_sample;
|
||||
- detail:账号清单+metrics 全字段+score 完整明细+anomalies+prev/baseline;
|
||||
@@ -280,6 +281,15 @@ async def test_dashboard_structure_and_kpis(make_client):
|
||||
"reactivated": 5}
|
||||
assert k["lifecycle"] == body["lifecycle"]
|
||||
|
||||
# 前窗环比(批次D):prev 窗 0827-0831 与基线窗种子重叠——
|
||||
# u1(14+14)×5 + u2(5+5)×5 = 190;宽表无 active_friends/串列 → 0
|
||||
pk = body["prev_kpis"]
|
||||
assert set(pk) == {"active_customers", "active_employees",
|
||||
"msg_total", "cust_threads"}
|
||||
assert pk == {"active_customers": 0, "active_employees": 2,
|
||||
"msg_total": 190, "cust_threads": 0}
|
||||
assert body["msg_delta"] == round((155 - 190) / 190, 3) # -0.184
|
||||
|
||||
# 趋势逐日 5 点;0901 = u1(1)+u2(20)+u3(10) 消息,宽表 active 合计 8,通话 2
|
||||
trend = body["communication_trend"]
|
||||
assert [t["day"] for t in trend] == [20260901 + i for i in range(5)]
|
||||
@@ -306,17 +316,39 @@ async def test_dashboard_structure_and_kpis(make_client):
|
||||
assert d["scored_count"] + d["insufficient_count"] + d["pending_count"] == 3
|
||||
assert "avg_score" in d
|
||||
|
||||
# 异常:critical 在前(u2),warning 其后按 affected_count desc
|
||||
# 异常:critical 在前(u2),warning 其后按 affected_count desc;
|
||||
# dashboard 卡片 enrich employee_name(批次D,前端跳员工详情用)
|
||||
anoms = body["anomalies"]
|
||||
assert anoms[0]["severity"] == "critical"
|
||||
assert anoms[0]["employee_user_id"] == "u2"
|
||||
assert anoms[0]["employee_name"] == "李四"
|
||||
assert all(a["severity"] == "critical" for a in anoms[:1])
|
||||
assert all(a["severity"] == "warning" for a in anoms[1:])
|
||||
assert all(a["employee_name"] == "张三" for a in anoms[1:])
|
||||
|
||||
assert body["action_summary"] == {"unreplied_2h": 1, "churn_real_30d": 0,
|
||||
"sensitive_pending": 0}
|
||||
|
||||
|
||||
async def test_dashboard_prev_zero_no_delta(make_client):
|
||||
"""前窗无数据(whatsapp 视图前窗零宽表)→ prev_kpis 四键全 0、
|
||||
msg_delta None(prev=0 不算环比,None 而非 0/负∞)。"""
|
||||
async def seed(s):
|
||||
await _seed_common(s)
|
||||
|
||||
client = await make_client(seed)
|
||||
r = await client.get("/api/management/dashboard",
|
||||
params={"channel": "whatsapp", "start": START,
|
||||
"end": END})
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["kpis"]["msg_total"] == 50 # 仅 u3 的 whatsapp 宽表
|
||||
assert body["prev_kpis"] == {"active_customers": 0,
|
||||
"active_employees": 0, "msg_total": 0,
|
||||
"cust_threads": 0}
|
||||
assert body["msg_delta"] is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- employees
|
||||
|
||||
|
||||
@@ -501,9 +533,11 @@ async def test_employee_detail_full(make_client):
|
||||
assert body["score"]["metrics_detail"]["reply_2h_rate"]["value"] == 0.2
|
||||
assert body["score"]["metrics_detail"]["fr_p90_ms"]["baseline"] == 60_000
|
||||
# anomalies + prev/baseline 原始值(prev 窗 0827-0831 与基线窗重叠:
|
||||
# 5 天 × msg_sent 14 = 70)
|
||||
# 5 天 × msg_sent 14 = 70);详情端点 anomalies 不带 employee_name
|
||||
# (自指无意义,仅 dashboard enrich)
|
||||
assert len(body["anomalies"]) == 2
|
||||
assert all(a["severity"] == "warning" for a in body["anomalies"])
|
||||
assert all("employee_name" not in a for a in body["anomalies"])
|
||||
assert body["prev"]["msg_sent"] == 70
|
||||
assert body["baseline"]["msg_sent"] == 70
|
||||
assert body["data_as_of"] == _ts(2026, 9, 3, 9, 0)
|
||||
|
||||
Reference in New Issue
Block a user