feat(analytics): 看板v2全平台口径——默认双渠道合计/拆分小字/双线趋势/跳转带query预选
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -344,3 +344,84 @@ async def test_action_counts(make_client, monkeypatch):
|
||||
"sensitive_pending": 1}
|
||||
|
||||
await make_client(seed)
|
||||
|
||||
|
||||
async def test_overview_all_channel(make_client, monkeypatch):
|
||||
"""看板 v2 全平台口径(channel=None):卡片=两渠道合计、by_channel 拆分、
|
||||
trend=合计、trend_by_channel 双序列(仅 all 时出现;单渠道不加键)。"""
|
||||
monkeypatch.setattr(metrics, "today_key", lambda: _TODAY)
|
||||
async def seed(session):
|
||||
await _seed(session) # wechat 当日:t1 friend 15 + r1 room 7 = 22
|
||||
# whatsapp 当日:w1 friend 6(全史首现=今日,首沟通落窗)
|
||||
session.add(MsgDailyStats(channel="whatsapp", owner_account_id="wa1",
|
||||
peer_kind="friend", peer_id="w1", day=20260904,
|
||||
send_cnt=4, recv_cnt=2, last_ts=1788500000000,
|
||||
last_is_send=True))
|
||||
await session.commit()
|
||||
|
||||
out = await metrics.overview(session, channel=None, scope="today")
|
||||
assert out["channel"] == "all"
|
||||
# 合计卡片(peer 跨渠道不碰撞:活跃客户/首沟通直接相加)
|
||||
assert out["cards"]["msg_total"] == 28 # 22 + 6
|
||||
assert out["cards"]["active_customers"] == 2 # t1 + w1
|
||||
assert out["cards"]["first_contact"] == 2
|
||||
# 拆分小字数据源
|
||||
assert out["by_channel"]["wechat"] == {
|
||||
"msg_total": 22, "active_customers": 1, "first_contact": 1}
|
||||
assert out["by_channel"]["whatsapp"] == {
|
||||
"msg_total": 6, "active_customers": 1, "first_contact": 1}
|
||||
# 趋势:合计单系列保持可用 + 双渠道序列(30 天窗末日有值)
|
||||
assert len(out["trend"]) == 30
|
||||
assert out["trend"][-1]["msg"] == 28
|
||||
assert out["trend"][-1]["active_customers"] == 2
|
||||
tbc = out["trend_by_channel"]
|
||||
assert len(tbc["wechat"]) == 30 and len(tbc["whatsapp"]) == 30
|
||||
assert tbc["wechat"][-1]["msg"] == 22
|
||||
assert tbc["whatsapp"][-1]["msg"] == 6
|
||||
# 通话量无渠道语义不拆:渠道序列 call_cnt 恒 0,总量走 trend
|
||||
assert tbc["wechat"][-1]["call_cnt"] == 0
|
||||
assert out["trend"][-1]["call_cnt"] == 1
|
||||
|
||||
# 单渠道:不加 by_channel/trend_by_channel 键(既有行为不破坏)
|
||||
single = await metrics.overview(session, channel="wechat", scope="today")
|
||||
assert single["cards"]["msg_total"] == 22
|
||||
assert "by_channel" not in single
|
||||
assert "trend_by_channel" not in single
|
||||
|
||||
await make_client(seed)
|
||||
|
||||
|
||||
async def test_action_counts_all(make_client, monkeypatch):
|
||||
"""all 口径行动计数:两渠道各一条未回 → unreplied_2h=2;sensitive_pending
|
||||
同样跨渠道合计(只计 pending)。"""
|
||||
monkeypatch.setattr(metrics, "_now_ms", lambda: 1756950000000)
|
||||
async def seed(session):
|
||||
now = 1756950000000
|
||||
h3 = 3 * 3600 * 1000
|
||||
for i, (ch, owner, peer) in enumerate(
|
||||
[("wechat", "wx1", "t1"), ("whatsapp", "wa1", "w1")]
|
||||
):
|
||||
session.add(MsgDailyStats(channel=ch, owner_account_id=owner,
|
||||
peer_kind="friend", peer_id=peer, day=20260904,
|
||||
send_cnt=5, recv_cnt=3, last_ts=now - h3,
|
||||
last_is_send=False))
|
||||
session.add(Message(msg_id=f"m{i}", channel=ch, owner_account_id=owner,
|
||||
talker_id=peer, timestamp=now - h3, is_send=False,
|
||||
type="text", text="在吗",
|
||||
fetched_at=dt.datetime(2026, 9, 4, 12, 0)))
|
||||
w = SensitiveWord(word="测试词")
|
||||
session.add(w)
|
||||
await session.flush()
|
||||
session.add(SensitiveHit(word_id=w.id, msg_id="s1", channel="wechat",
|
||||
disposition="pending"))
|
||||
session.add(SensitiveHit(word_id=w.id, msg_id="s2", channel="whatsapp",
|
||||
disposition="pending"))
|
||||
session.add(SensitiveHit(word_id=w.id, msg_id="s3", channel="whatsapp",
|
||||
disposition="confirmed"))
|
||||
await session.commit()
|
||||
|
||||
out = await metrics.action_counts(session, channel=None)
|
||||
assert out == {"unreplied_2h": 2, "churn_real_30d": 0,
|
||||
"sensitive_pending": 2}
|
||||
|
||||
await make_client(seed)
|
||||
|
||||
Reference in New Issue
Block a user