feat(admin): 数据总览按客迹视觉V1重做(周期卡/趋势双线/渠道条形/最近访问)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,8 @@ def _iso(dt):
|
||||
|
||||
def _row(visitor, last_session, online_cutoff, ft=None):
|
||||
"""列表/详情共用行字段。last_source 依赖最近会话(由调用方批量取好传入,防 N+1)。
|
||||
channel 等归因五字段来自该访客 first_touch 分类(无分类行 → 空串,前端回落 first_source 展示)。"""
|
||||
channel 等归因五字段来自该访客 first_touch 分类(无分类行 → 空串,前端回落 first_source 展示)。
|
||||
last_path 是最近一条事件的 path(_annotate 的 Subquery 注解,同样无 N+1)。"""
|
||||
return {
|
||||
"visitor_id": visitor.visitor_id,
|
||||
# 站点归属:visitor.site 需随行 select_related("site"),否则逐行多一条查询
|
||||
@@ -55,6 +56,7 @@ def _row(visitor, last_session, online_cutoff, ft=None):
|
||||
"last_source": _source(last_session.referrer_domain, last_session.utm)
|
||||
if last_session else "直接访问", # 无会话访客(仅采集异常场景)
|
||||
"first_landing_path": visitor.first_landing_path, # 列表首触来源 tooltip 用(详情本就输出)
|
||||
"last_path": visitor.last_event_path or "", # 最近一条事件 path(总览"浏览页面"列)
|
||||
"channel": ft.channel if ft else "",
|
||||
"platform": ft.platform if ft else "",
|
||||
"variant": ft.variant if ft else "",
|
||||
@@ -87,18 +89,23 @@ def _session_summary(s):
|
||||
|
||||
|
||||
def _annotate(qs):
|
||||
"""会话数/有效停留/最近会话标记一次注解到位。
|
||||
"""会话数/有效停留/最近会话/最近事件路径一次注解到位。
|
||||
|
||||
last_source 不逐行 sessions.order_by("-started_at").first()(页大小 20 即 N+1):
|
||||
先用相关子查询把每个访客最近会话的 pk 标到行上(走 (visitor,-started_at) 索引),
|
||||
分页后一次 IN 查询取回整页会话——全程只多 2 条 SQL。
|
||||
last_path 同理用相关子查询取最近一条事件的 path(走 (site,visitor,-occurred_at) 索引),
|
||||
-pk 平局次序跨请求稳定;无事件访客注解为 NULL,_row 收敛为空串。
|
||||
"""
|
||||
latest = (VisitSession.objects.filter(visitor=OuterRef("pk"))
|
||||
.order_by("-started_at", "-pk")) # -pk 平局次序跨请求稳定
|
||||
last_event = (Event.objects.filter(visitor=OuterRef("pk"))
|
||||
.order_by("-occurred_at", "-pk"))
|
||||
return qs.annotate(
|
||||
session_count=Count("sessions"),
|
||||
total_stay_ms=Sum("sessions__stay_ms"), # 有效停留口径(非 duration_ms)
|
||||
latest_session_pk=Subquery(latest.values("pk")[:1]),
|
||||
last_event_path=Subquery(last_event.values("path")[:1]),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user