package vip import ( "context" "net/http" "strconv" "strings" "time" "chatapp3-golang/internal/model" ) // PageOrders returns VIP purchase records for the admin page. func (s *Service) PageOrders( ctx context.Context, sysOrigin string, userID int64, status string, orderType string, cursor int, limit int, ) (*OrderPageResponse, error) { sysOrigin = normalizeSysOrigin(sysOrigin) if sysOrigin == "" { return nil, NewAppError(http.StatusBadRequest, "bad_request", "sysOrigin is required") } page, size := normalizePage(cursor, limit) query := s.db.WithContext(ctx).Model(&model.VipOrderRecord{}).Where("sys_origin = ?", sysOrigin) if userID > 0 { query = query.Where("user_id = ?", userID) } if normalizedStatus := strings.ToUpper(strings.TrimSpace(status)); normalizedStatus != "" { query = query.Where("status = ?", normalizedStatus) } if normalizedType := strings.ToUpper(strings.TrimSpace(orderType)); normalizedType != "" { query = query.Where("order_type = ?", normalizedType) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, err } records := make([]VipOrderPayload, 0) if total > 0 { var rows []model.VipOrderRecord if err := query. Order("create_time desc"). Order("id desc"). Offset((page - 1) * size). Limit(size). Find(&rows).Error; err != nil { return nil, err } records = make([]VipOrderPayload, 0, len(rows)) for _, row := range rows { records = append(records, orderPayloadFromModel(row)) } } return &OrderPageResponse{Records: records, Total: total}, nil } // PageUserStates returns the current VIP state rows for the admin page. func (s *Service) PageUserStates( ctx context.Context, sysOrigin string, userID int64, status string, cursor int, limit int, ) (*UserStatePageResponse, error) { sysOrigin = normalizeSysOrigin(sysOrigin) if sysOrigin == "" { return nil, NewAppError(http.StatusBadRequest, "bad_request", "sysOrigin is required") } now := time.Now() if err := s.expireDueStates(ctx, sysOrigin, now); err != nil { return nil, err } page, size := normalizePage(cursor, limit) query := s.db.WithContext(ctx).Model(&model.UserVipState{}).Where("sys_origin = ?", sysOrigin) if userID > 0 { query = query.Where("user_id = ?", userID) } if normalizedStatus := strings.ToUpper(strings.TrimSpace(status)); normalizedStatus != "" { query = query.Where("status = ?", normalizedStatus) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, err } records := make([]UserVipStatePayload, 0) if total > 0 { var rows []model.UserVipState if err := query. Order("update_time desc"). Order("id desc"). Offset((page - 1) * size). Limit(size). Find(&rows).Error; err != nil { return nil, err } resourceIDs := make([]int64, 0, len(rows)*5) for idx := range rows { resourceIDs = appendResourceIDsFromState(resourceIDs, &rows[idx]) } resources, err := s.loadResourceLookup(ctx, resourceIDs) if err != nil { return nil, err } records = make([]UserVipStatePayload, 0, len(rows)) for idx := range rows { records = append(records, statePayloadFromModelWithResources(&rows[idx], now, resources)) } } return &UserStatePageResponse{Records: records, Total: total}, nil } // PageUserOrders returns the current user's VIP order records. func (s *Service) PageUserOrders(ctx context.Context, user AuthUser, cursor int, limit int) (*OrderPageResponse, error) { sysOrigin, err := normalizeUser(user) if err != nil { return nil, err } return s.PageOrders(ctx, sysOrigin, user.UserID, "", "", cursor, limit) } func (s *Service) expireDueStates(ctx context.Context, sysOrigin string, now time.Time) error { updates := map[string]any{ "level": 0, "level_code": "", "display_name": "", "status": statusExpired, "badge_resource_id": 0, "badge_name": "", "badge_url": "", "avatar_frame_resource_id": 0, "avatar_frame_name": "", "avatar_frame_url": "", "entry_effect_resource_id": 0, "entry_effect_name": "", "entry_effect_url": "", "chat_bubble_resource_id": 0, "chat_bubble_name": "", "chat_bubble_url": "", "float_picture_resource_id": 0, "float_picture_name": "", "float_picture_url": "", "update_time": now, } return s.db.WithContext(ctx). Model(&model.UserVipState{}). Where("sys_origin = ? AND status = ? AND expire_at <= ?", sysOrigin, statusActive, now). Updates(updates).Error } // ParseUserID parses optional userId filters from query strings. func ParseUserID(raw string) int64 { value := strings.TrimSpace(raw) if value == "" { return 0 } parsed, err := strconv.ParseInt(value, 10, 64) if err != nil { return 0 } return parsed }