package business import ( "context" "gorm.io/gorm" "kra/internal/biz/business" ) type channelPortraitRepo struct{ data Provider } func NewChannelPortraitRepo(data Provider) business.ChannelPortraitRepo { return &channelPortraitRepo{data: data} } func (r *channelPortraitRepo) GameCount(ctx context.Context, key business.ChannelKey) (*int64, error) { db := r.data.DB().WithContext(ctx) available, err := businessTableAvailable(db, "tab_promote_apply") if err != nil { return nil, err } if !available { return nil, nil } var count int64 if err := db.Table("tab_promote_apply").Where("source_db = ? AND promote_id = ? AND status = 1", key.SourceDB, key.ID).Distinct("game_id").Count(&count).Error; err != nil { return nil, business.ErrStorage } return &count, nil } func (r *channelPortraitRepo) EarliestDate(ctx context.Context, scope business.ChannelGameScope) (string, bool, error) { db := r.data.DB().WithContext(ctx) available, err := businessTableAvailable(db, "tab_sw_report_day") if err != nil { return "", false, err } if !available { return "", false, nil } mode := 0 if scope.IDCardDedup { mode = 1 } var result struct{ FirstDate *string } q := db.Table("tab_sw_report_day r").Where("r.source_db = ? AND r.dedup_mode = ? AND r.game_id > 0", scope.Root.SourceDB, mode).Where("(r.source_db,r.promote_id) IN (?)", channelGameTree(db, scope).Select("p.source_db,p.id")) if err := q.Select("CAST(MIN(r.stat_date) AS CHAR) AS first_date").Scan(&result).Error; err != nil { return "", false, business.ErrStorage } if result.FirstDate == nil { return "", true, nil } return *result.FirstDate, true, nil } func channelTierKeys(db *gorm.DB, scope business.ChannelGameScope) *gorm.DB { mode := 0 if scope.IDCardDedup { mode = 1 } return db.Table("tab_sw_report_day_key r").Where("r.source_db = ? AND r.dedup_mode = ? AND r.game_id > 0 AND r.metric = 1 AND r.stat_date >= ? AND r.stat_date <= ? AND r.identity_key IS NOT NULL", scope.Root.SourceDB, mode, scope.BeginDate, scope.EndDate).Where("(r.source_db,r.promote_id) IN (?)", channelGameTree(db, scope).Select("p.source_db,p.id")) } func (r *channelPortraitRepo) TierData(ctx context.Context, scope business.ChannelGameScope) (*business.ChannelTierData, error) { result := &business.ChannelTierData{Available: true, RegisterKeys: []string{}, Payments: []*business.ChannelIdentityPay{}} db := r.data.DB().WithContext(ctx) available, err := businessTableAvailable(db, "tab_sw_report_day_key") if err != nil { return nil, err } if !available { result.Available = false return result, nil } identity := portraitIdentity(db, scope.IDCardDedup) if err := channelTierKeys(db, scope).Select("DISTINCT " + identity).Scan(&result.RegisterKeys).Error; err != nil { return nil, business.ErrStorage } if len(result.RegisterKeys) == 0 { if err := channelTierKeys(db, scope).Select("COUNT(DISTINCT " + identity + ")").Scan(&result.FallbackCount).Error; err != nil { return nil, business.ErrStorage } return result, nil } tables := []string{"tab_spend"} if scope.IDCardDedup { tables = append(tables, "tab_user") } for _, table := range tables { available, err := businessTableAvailable(db, table) if err != nil { return nil, err } if !available { result.Available = false return result, nil } } // 分层金额按历史成功支付累计,不受画像周期或注册日期范围限制。 q := db.Table("tab_spend s").Where("s.source_db = ? AND s.pay_status = 1", scope.Root.SourceDB).Where("(s.source_db,s.promote_id) IN (?)", channelGameTree(db, scope).Select("p.source_db,p.id")) if scope.IDCardDedup { var rows []struct { IDCard *string `gorm:"column:idcard"` Amount string } if err := q.Joins("JOIN tab_user u ON u.id=s.user_id AND u.source_db=s.source_db").Where("u.idcard IS NOT NULL AND TRIM(u.idcard) <> ''").Select("u.idcard AS idcard,COALESCE(SUM(s.pay_amount),0) AS amount").Group("u.idcard").Scan(&rows).Error; err != nil { return nil, business.ErrStorage } for _, row := range rows { result.Payments = append(result.Payments, &business.ChannelIdentityPay{IDCard: row.IDCard, Amount: row.Amount}) } } else { var rows []struct { UserID *uint64 Amount string } if err := q.Select("s.user_id,COALESCE(SUM(s.pay_amount),0) AS amount").Group("s.user_id").Scan(&rows).Error; err != nil { return nil, business.ErrStorage } for _, row := range rows { result.Payments = append(result.Payments, &business.ChannelIdentityPay{UserID: row.UserID, Amount: row.Amount}) } } return result, nil }