feat(adtracking): 新增推广链接追踪与数据大盘,支持自定义短码、注册与下单归因及二维码物料生成

1. 数据库新增 000064_ad_tracking.sql 迁移,创建 ad_tracking_links 和 ad_tracking_clicks 表,并在 users、rental_orders 增加归因字段
2. 后端新增 adtracking 模块,挂载 GET /r/:code 302 智能重定向、点击流水异步记录、转化率/GMV聚合统计及管理接口
3. 用户认证 (auth) 与订单创建 (order) 链路贯通,实现注册用户与订单成交推广短码全链路归因
4. 前端管理后台左侧新增【推广追踪】目录,支持大盘指标总览、推广链接 CRUD、状态启停、一键复制短链及二维码下载 (PNG)
This commit is contained in:
yml2213
2026-09-10 11:05:47 +08:00
parent 33ee8408e9
commit 2b11d70ebe
25 changed files with 2304 additions and 36 deletions
+28 -17
View File
@@ -3,6 +3,7 @@ package auth
import (
"context"
"errors"
"strings"
"time"
"hfb_sys/backend/internal/model"
@@ -57,16 +58,21 @@ func (r *UserRepository) UpdateProfile(ctx context.Context, id uint64, nickname
return r.FindByID(ctx, id)
}
func (r *UserRepository) FindOrCreateByPhone(ctx context.Context, phone string) (*model.User, error) {
func (r *UserRepository) FindOrCreateByPhone(ctx context.Context, phone string, trackCode ...string) (*model.User, error) {
now := time.Now()
var code string
if len(trackCode) > 0 {
code = strings.TrimSpace(trackCode[0])
}
user := model.User{
Phone: phone,
Nickname: "用户" + phone[len(phone)-4:],
RealnameStatus: "unverified",
RiskStatus: "normal",
CreditScore: 100,
Status: "active",
LastLoginAt: &now,
Phone: phone,
Nickname: "用户" + phone[len(phone)-4:],
RealnameStatus: "unverified",
RiskStatus: "normal",
CreditScore: 100,
Status: "active",
RegisterTrackCode: code,
LastLoginAt: &now,
}
err := r.db.WithContext(ctx).Clauses(clause.OnConflict{
@@ -96,17 +102,22 @@ func (r *UserRepository) SetPassword(ctx context.Context, userID uint64, hash st
return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", userID).Update("password_hash", hash).Error
}
func (r *UserRepository) RegisterWithPassword(ctx context.Context, phone string, hash string) (*model.User, error) {
func (r *UserRepository) RegisterWithPassword(ctx context.Context, phone string, hash string, trackCode ...string) (*model.User, error) {
now := time.Now()
var code string
if len(trackCode) > 0 {
code = strings.TrimSpace(trackCode[0])
}
user := model.User{
Phone: phone,
PasswordHash: hash,
Nickname: "用户" + phone[len(phone)-4:],
RealnameStatus: "unverified",
RiskStatus: "normal",
CreditScore: 100,
Status: "active",
LastLoginAt: &now,
Phone: phone,
PasswordHash: hash,
Nickname: "用户" + phone[len(phone)-4:],
RealnameStatus: "unverified",
RiskStatus: "normal",
CreditScore: 100,
Status: "active",
RegisterTrackCode: code,
LastLoginAt: &now,
}
err := r.db.WithContext(ctx).Create(&user).Error