feat(management): 驾驶舱KPI环比(prev_kpis+delta)+异常卡带员工名跳详情+列表进详情带筛选

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-10 12:20:28 +08:00
parent be0d6f844e
commit 422a726ee8
7 changed files with 160 additions and 13 deletions
+37 -3
View File
@@ -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)