fix(cps): 群内微信用户按"本群点击"算,不用 first_group_id
first_group_id 只记首次授权群;同一用户(cookie 已存)再去别的群不再走授权回调, 会被漏算(实测:用户首次在群47授权,再去群52点击,群52详情显示0)。 改为:在本群有带 openid 点击的 distinct openid 即本群用户,关联 cps_wx_user 画像。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -474,44 +474,53 @@ def group_order_daily(
|
||||
|
||||
|
||||
def group_wx_users(db: Session, *, group_id: int, limit: int = 200) -> list[dict]:
|
||||
"""群内微信用户(首次来源 first_group_id=group_id)+ 每人在该群的 visit/copy 次数(领券画像)。
|
||||
"""该群来过的微信用户:在本群有带 openid 点击的所有用户 + 本群 visit/copy 次数 + 画像。
|
||||
|
||||
按首次进入倒序。copy 次数 = 该用户在该群点了几次「复制口令」(领券意向),visit = 进落地页次数。
|
||||
用「本群点击」判定归属,而非 cps_wx_user.first_group_id —— 同一用户会在多个群活动,
|
||||
first_group_id 只记首次授权群,会漏掉"先在别处授权、cookie 已存、又来本群"的用户。
|
||||
copy=本群点「复制口令」次数(领券意向),visit=进落地页次数。按本群首次点击倒序。
|
||||
昵称/头像来自授权画像;美团/京东群只 302 跳转、无 userinfo 触发点,故多为空。
|
||||
"""
|
||||
users = (
|
||||
db.execute(
|
||||
select(CpsWxUser)
|
||||
.where(CpsWxUser.first_group_id == group_id)
|
||||
.order_by(desc(CpsWxUser.first_seen))
|
||||
.limit(limit)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
if not users:
|
||||
return []
|
||||
openids = [u.openid for u in users]
|
||||
stat: dict[str, dict] = {}
|
||||
rows = db.execute(
|
||||
select(CpsClick.openid, CpsClick.event_type, func.count())
|
||||
.where(CpsClick.group_id == group_id)
|
||||
.where(CpsClick.openid.in_(openids))
|
||||
.where(CpsClick.openid.is_not(None))
|
||||
.group_by(CpsClick.openid, CpsClick.event_type)
|
||||
).all()
|
||||
if not rows:
|
||||
return []
|
||||
stat: dict[str, dict] = {}
|
||||
for openid, event_type, cnt in rows:
|
||||
s = stat.setdefault(openid, {"visit": 0, "copy": 0})
|
||||
if event_type == "copy":
|
||||
s["copy"] = cnt
|
||||
else:
|
||||
s["visit"] = cnt
|
||||
return [
|
||||
openids = list(stat.keys())
|
||||
# 本群每个 openid 的首次点击时间(排序 + 展示"首次进入")
|
||||
first_seen = dict(
|
||||
db.execute(
|
||||
select(CpsClick.openid, func.min(CpsClick.clicked_at))
|
||||
.where(CpsClick.group_id == group_id)
|
||||
.where(CpsClick.openid.is_not(None))
|
||||
.group_by(CpsClick.openid)
|
||||
).all()
|
||||
)
|
||||
# 关联画像(未授权 userinfo 的昵称/头像为空)
|
||||
users = {
|
||||
u.openid: u
|
||||
for u in db.execute(select(CpsWxUser).where(CpsWxUser.openid.in_(openids))).scalars().all()
|
||||
}
|
||||
result = [
|
||||
{
|
||||
"openid": u.openid,
|
||||
"nickname": u.nickname,
|
||||
"headimgurl": u.headimgurl,
|
||||
"first_seen": u.first_seen,
|
||||
"visit_count": stat.get(u.openid, {}).get("visit", 0),
|
||||
"copy_count": stat.get(u.openid, {}).get("copy", 0),
|
||||
"openid": openid,
|
||||
"nickname": users[openid].nickname if openid in users else None,
|
||||
"headimgurl": users[openid].headimgurl if openid in users else None,
|
||||
"first_seen": first_seen.get(openid),
|
||||
"visit_count": stat[openid]["visit"],
|
||||
"copy_count": stat[openid]["copy"],
|
||||
}
|
||||
for u in users
|
||||
for openid in openids
|
||||
]
|
||||
result.sort(key=lambda x: x["first_seen"], reverse=True)
|
||||
return result[:limit]
|
||||
|
||||
Reference in New Issue
Block a user