Files
server-core/app/api/routers/invite.py
T

101 lines
3.7 KiB
Python

"""邀请归因 API:邀请码、小程序码、分享/扫码归因、邀请统计。"""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field
from ...infrastructure.repositories import Database
from ...services import invite_service
from ..dependencies import get_current_user, get_db
router = APIRouter(prefix="/invite", tags=["邀请归因"])
class ShareRequest(BaseModel):
channel: str = Field(default="share_app", description="share_app|share_timeline|qrcode|link")
scene: str = Field(default="", description="场景:test_result|profile|home等")
env: str = Field(default="trial", description="trial|release")
class ScanRequest(BaseModel):
inviter: str = Field(description="邀请人ID或邀请码")
scene: str = Field(default="", description="扫码场景值")
env: str = Field(default="trial", description="trial|release")
class QrcodeRequest(BaseModel):
scene: str = Field(default="home", description="场景:home|test_result|profile")
page: str = Field(default="pages/index/index", description="小程序页面路径")
env: str = Field(default="trial", description="trial|release")
width: int = Field(default=430, description="小程序码宽度")
@router.get("/me", summary="获取我的邀请码和统计")
async def get_my_invite(user: dict = Depends(get_current_user), db: Database = Depends(get_db)):
stats = await invite_service.get_invite_stats(db, user["id"])
return stats
@router.get("/qrcode", summary="生成带邀请参数的小程序码")
async def get_invite_qrcode(
scene: str = "home",
page: str = "pages/index/index",
env: str = "trial",
width: int = 430,
user: dict = Depends(get_current_user),
db: Database = Depends(get_db),
):
result = await invite_service.get_wxacode(db, user["id"], scene=scene, page=page, env=env, width=width)
if not result.get("success"):
raise HTTPException(status_code=500, detail=f"生成小程序码失败: {result.get('error')}")
# 返回 base64 图片
import base64
img_b64 = base64.b64encode(result["image"]).decode()
return {
"image": f"data:image/png;base64,{img_b64}",
"scene": result["scene"],
"invite_code": result["invite_code"],
}
@router.post("/share", summary="记录分享行为")
async def record_share(
req: ShareRequest,
request: Request,
user: dict = Depends(get_current_user),
db: Database = Depends(get_db),
):
ip = request.client.host if request.client else ""
await invite_service.record_share(db, user["id"], channel=req.channel, scene=req.scene, env=req.env, ip=ip)
return {"success": True}
@router.post("/scan", summary="记录扫码行为(无需登录)")
async def record_scan(req: ScanRequest, request: Request, db: Database = Depends(get_db)):
ip = request.client.host if request.client else ""
await invite_service.record_scan(db, req.inviter, channel="qrcode", scene=req.scene, env=req.env, ip=ip)
return {"success": True}
@router.get("/invitees", summary="获取我邀请的用户列表")
async def get_invitees(
user: dict = Depends(get_current_user),
db: Database = Depends(get_db),
):
invitees = await db.users.get_invitees(user["id"])
from ...infrastructure.oss import resolve_url
return {
"total": len(invitees),
"list": [
{
"id": u["id"],
"nickname": u.get("nickname", ""),
"avatar": resolve_url(u.get("avatar", "")),
"phone": u.get("phone", ""),
"invited_at": u.get("invited_at", ""),
"created_at": u.get("created_at", ""),
}
for u in invitees
],
}