3a40f617bd
- model: cps_group.platforms 多选 / cps_activity.payload(淘口令/京东链接) / cps_link.sid 可空 + 复制统计 - admin API: 群与活动平台多选、批量生成落地页短链 referral-links、对账字段可空 - 落地页 cps_redirect: 淘宝展示淘口令(记 copy 事件) / 京东 302 / 美团原逻辑 - 迁移 cps_v2_platforms: 加 platforms/payload/event_type 列, sid 放宽可空(含 downgrade) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
2.8 KiB
Python
58 lines
2.8 KiB
Python
"""CPS 群发短链(cps_link)+ 点击事件(cps_click)。
|
|
|
|
群发券链接套一层我们自己的短链 `/c/{code}`:用户点 → 记一条 cps_click → 302 跳
|
|
target_url(美团短链,微信可打开)。据此统计点击 PV/UV(按群/活动/时段),配合 cps_order
|
|
的下单/佣金做"点击→下单→佣金"漏斗。group_id/sid 在 cps_click 里冗余一份,统计直接按
|
|
群聚合点击、不必 join cps_link。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import DateTime, Integer, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
class CpsLink(Base):
|
|
__tablename__ = "cps_link"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
# 短码:发群链接 /c/{code} 的 code,全局唯一。
|
|
code: Mapped[str] = mapped_column(String(16), unique=True, index=True, nullable=False)
|
|
group_id: Mapped[int] = mapped_column(Integer, index=True, nullable=False)
|
|
activity_id: Mapped[int] = mapped_column(Integer, index=True, nullable=False)
|
|
# 仅美团 link 有 sid(渠道追踪);淘宝/京东无 sid。
|
|
sid: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
|
|
platform: Mapped[str] = mapped_column(String(20), nullable=False, default="meituan")
|
|
# 跳转/落地目标: 美团短链 / 京东链接(302 跳) / 淘宝整段淘口令文本(H5 落地页复制)。
|
|
target_url: Mapped[str] = mapped_column(String(2048), nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
|
|
def __repr__(self) -> str: # pragma: no cover
|
|
return f"<CpsLink id={self.id} code={self.code!r} sid={self.sid!r}>"
|
|
|
|
|
|
class CpsClick(Base):
|
|
__tablename__ = "cps_click"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
link_id: Mapped[int] = mapped_column(Integer, index=True, nullable=False)
|
|
group_id: Mapped[int] = mapped_column(Integer, index=True, nullable=False) # 冗余,按群聚合快
|
|
sid: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True) # 冗余(淘宝/京东无)
|
|
# 事件类型: visit(进落地页/被跳转) | copy(淘宝落地页点了"复制口令")
|
|
event_type: Mapped[str] = mapped_column(
|
|
String(16), nullable=False, default="visit", server_default="visit"
|
|
)
|
|
ip: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
ua: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
|
clicked_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), index=True, nullable=False
|
|
)
|
|
|
|
def __repr__(self) -> str: # pragma: no cover
|
|
return f"<CpsClick id={self.id} link_id={self.link_id} group_id={self.group_id}>"
|