package business import ( "context" "math" "strconv" "strings" "time" "unicode/utf16" "kra/internal/biz/business" "kra/internal/service/dto" ) type ChannelUsecase interface { List(context.Context, business.ChannelFilter, ...business.ListOption) (*business.ChannelPage, error) BindOptions(context.Context, string) ([]*business.Binding, error) Create(context.Context, *business.ChannelCreate) (*business.ChannelCreateResult, error) Games(context.Context, business.ChannelKey) ([]*business.ChannelGame, error) } type ChannelService struct{ uc ChannelUsecase } func NewChannelService(uc *business.ChannelUsecase) *ChannelService { return &ChannelService{uc: uc} } func (s *ChannelService) List(ctx context.Context, req *dto.ChannelQuery) (*dto.ChannelPage, error) { if req == nil { return nil, business.ErrChannelInput } sources, err := normalizePlatforms(req.Sources) if err != nil { return nil, err } page, size := req.Page, req.PageSize if page < 1 { page = 1 } if size < 1 { size = 10 } if size > 500 { size = 500 } if page > int(^uint(0)>>1)/size { return nil, business.ErrChannelInput } filter := business.ChannelFilter{Sources: sources, BusierUserID: req.BusierUserID, BusierAccount: strings.TrimSpace(req.BusierAccount), Keyword: strings.TrimSpace(req.Keyword), Level: req.Level, RegisterType: req.RegisterType, Status: req.Status, LockStatus: req.LockStatus, Effective: req.Effective} filter.Phone, filter.SettlementDays = strings.TrimSpace(req.Phone), req.SettlementDays filter.SortField, filter.Ascending = req.SortField, req.SortOrder == "asc" if filter.SortField != "" && filter.SortField != "createdAt" || filter.SettlementDays != nil && *filter.SettlementDays < 1 { return nil, business.ErrChannelInput } for _, pair := range []struct { begin, end string outBegin, outEnd **time.Time }{ {req.CreatedBegin, req.CreatedEnd, &filter.CreatedBegin, &filter.CreatedEnd}, {req.LoginBegin, req.LoginEnd, &filter.LoginBegin, &filter.LoginEnd}, } { parsed, err := analyticsRequest(&dto.AnalyticsQuery{BeginTime: pair.begin, EndTime: pair.end}) if err != nil { return nil, business.ErrChannelInput } *pair.outBegin, *pair.outEnd = parsed.StartDate, parsed.EndDate } result, err := s.uc.List(ctx, filter, business.ListOffset((page-1)*size), business.ListLimit(size)) if err != nil { return nil, err } out := &dto.ChannelPage{Rows: []*dto.ChannelResponse{}, Total: result.Total, Available: result.Available} if result.StatusCounts != nil { out.StatusCounts = &dto.ChannelStatusCounts{Normal: result.StatusCounts.Normal, Locked: result.StatusCounts.Locked, Terminated: result.StatusCounts.Terminated} } for _, c := range result.Rows { out.Rows = append(out.Rows, &dto.ChannelResponse{ID: c.ID, SourceDB: c.SourceDB, PlatformName: business.PlatformName(c.SourceDB), Account: c.Account, Nickname: c.Nickname, Level: c.Level, ParentID: c.ParentID, ParentName: c.ParentName, RealName: c.RealName, RegisterType: c.RegisterType, BusierID: c.BusierID, BusierUserID: c.BusierUserID, BusierDisplayName: c.BusinessDisplayName(), Status: c.Status, LockStatus: c.LockStatus, GameCount: c.GameCount, PlayerCount: c.PlayerCount, TotalPayAmount: c.TotalPayAmount, Effective: c.QualifiedAt != nil, QualifiedAt: c.QualifiedAt, CreatedAt: c.CreatedUnix, LastLoginAt: c.LastLoginUnix, Phone: c.Phone, SettlementDays: c.SettlementDays}) } return out, nil } func (s *ChannelService) BindOptions(ctx context.Context, source string) ([]*dto.ChannelBindOption, error) { rows, err := s.uc.BindOptions(ctx, source) if err != nil { return nil, err } out := make([]*dto.ChannelBindOption, 0, len(rows)) for _, b := range rows { out = append(out, &dto.ChannelBindOption{SourceDB: b.SourceDB, PlatformBusierID: b.BusierID, Account: b.Account, UserID: b.UserID}) } return out, nil } func (s *ChannelService) Create(ctx context.Context, req *dto.ChannelCreateRequest) (*dto.ChannelCreateResult, error) { if req == nil || len(utf16.Encode([]rune(req.SourceDB))) > 10 || len(utf16.Encode([]rune(req.Account))) > 30 { return nil, business.ErrChannelInput } id, err := strconv.ParseUint(req.PlatformBusierID.String(), 10, 32) if err != nil || id == 0 || id > math.MaxInt32 { return nil, business.ErrChannelBinding } registerType := 0 if req.RegisterType != nil { registerType = *req.RegisterType } if registerType > math.MaxInt32 || registerType < math.MinInt32 { return nil, business.ErrChannelInput } result, err := s.uc.Create(ctx, &business.ChannelCreate{SourceDB: req.SourceDB, Account: req.Account, Password: req.Password, BusierID: id, RegisterType: registerType}) if err != nil { return nil, err } return &dto.ChannelCreateResult{ID: result.ID, SourceDB: result.SourceDB}, nil } func (s *ChannelService) Games(ctx context.Context, req *dto.ChannelGameQuery) ([]*dto.ChannelGameResponse, error) { if req == nil || req.PromoteID == 0 { return nil, business.ErrChannelInput } games, err := s.uc.Games(ctx, business.ChannelKey{SourceDB: req.SourceDB, ID: req.PromoteID}) if err != nil { return nil, err } out := make([]*dto.ChannelGameResponse, 0, len(games)) for _, game := range games { out = append(out, &dto.ChannelGameResponse{GameID: game.ID, GameName: game.Name, RegisterCount: game.RegisterCount, PayAmount: game.PayAmount}) } return out, nil }