feat: 访客列表站点归属显示与筛选

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-16 14:33:39 +08:00
parent 15ad3fb200
commit 58659b0ec9
4 changed files with 100 additions and 10 deletions
+33 -4
View File
@@ -74,10 +74,10 @@ def test_list_fields_and_default_bot_excluded(client, member_user):
assert d["total"] == 2 and d["page"] == 1 and len(d["list"]) == 2
assert [x["visitor_id"] for x in d["list"]] == ["v1", "v2"] # last_seen 倒序
row = d["list"][0]
assert set(row) == {"visitor_id", "country", "province", "city", "device_type", "os",
"browser", "language", "first_seen_at", "last_seen_at", "visit_count",
"active_days", "session_count", "total_stay_ms", "first_source",
"last_source", "online"}
assert set(row) == {"visitor_id", "site_id", "site_name", "country", "province", "city",
"device_type", "os", "browser", "language", "first_seen_at",
"last_seen_at", "visit_count", "active_days", "session_count",
"total_stay_ms", "first_source", "last_source", "online"}
assert row["country"] == "中国" and row["os"] == "Windows" and row["browser"] == "Chrome"
assert row["session_count"] == 2
assert row["total_stay_ms"] == 150000 # 120000+30000,有效停留口径
@@ -125,6 +125,34 @@ def test_list_filters_and_search(client, member_user):
assert ids(d) == ["old-visitor"] # last_seen 落在昨天
def test_list_site_fields_and_site_filter(client, member_user):
_auth(client, member_user)
site_a = Site.objects.create(name="站点A", domains=["a.com"])
site_b = Site.objects.create(name="站点B", domains=["b.com"])
_visitor(site_a, "va", last_seen=timezone.now())
_visitor(site_b, "vb", last_seen=timezone.now() - timedelta(hours=1))
d = client.get("/api/admin/visitors").json()["data"] # 缺省聚合全部站点
assert d["total"] == 2 and len(d["list"]) == 2
by_id = {x["visitor_id"]: x for x in d["list"]}
assert by_id["va"]["site_id"] == site_a.site_id and by_id["va"]["site_name"] == "站点A"
assert by_id["vb"]["site_id"] == site_b.site_id and by_id["vb"]["site_name"] == "站点B"
d = client.get("/api/admin/visitors", {"site": site_b.site_id}).json()["data"]
assert d["total"] == 1 and [x["visitor_id"] for x in d["list"]] == ["vb"] # 只剩本站访客
def test_list_site_not_found(client, member_user):
_auth(client, member_user)
site = Site.objects.create(name="s", domains=["a.com"])
_visitor(site, "v1", last_seen=timezone.now())
r = client.get("/api/admin/visitors", {"site": "site_nope"})
assert r.status_code == 404
body = r.json()
assert body["code"] == 404 and body["data"] is None and body["message"] == "site_not_found"
def test_list_pagination_and_order(client, member_user):
_auth(client, member_user)
site = Site.objects.create(name="s", domains=["a.com"])
@@ -153,6 +181,7 @@ def test_detail_shape(client, member_user):
r = client.get("/api/admin/visitors/v1")
assert r.status_code == 200
d = r.json()["data"]
assert d["site_id"] == site.site_id and d["site_name"] == "s" # 详情同样输出站点归属
assert d["screen"] == "1920x1080" and d["timezone_name"] == "Asia/Shanghai"
assert d["last_ip"] == "1.2.3.4" and d["first_utm"] == {"utm_source": "google"}
assert d["first_landing_path"] == "/landing" and d["first_referrer_domain"] == "google.com"