feat: add admin affiliate record pages

This commit is contained in:
lyen1688
2026-05-03 15:43:56 +08:00
parent 47fb38bca1
commit 6a41cf6a51
13 changed files with 1277 additions and 0 deletions

View File

@@ -2,8 +2,11 @@ package admin
import (
"strconv"
"strings"
"time"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/pkg/timezone"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
@@ -181,3 +184,108 @@ func (h *AffiliateHandler) LookupUsers(c *gin.Context) {
}
response.Success(c, result)
}
// GetUserOverview returns one user's affiliate overview.
// GET /api/v1/admin/affiliates/users/:user_id/overview
func (h *AffiliateHandler) GetUserOverview(c *gin.Context) {
userID, err := strconv.ParseInt(c.Param("user_id"), 10, 64)
if err != nil || userID <= 0 {
response.BadRequest(c, "Invalid user_id")
return
}
overview, err := h.affiliateService.AdminGetUserOverview(c.Request.Context(), userID)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Success(c, overview)
}
// ListInviteRecords returns all inviter-invitee relationships.
// GET /api/v1/admin/affiliates/invites
func (h *AffiliateHandler) ListInviteRecords(c *gin.Context) {
page, pageSize := response.ParsePagination(c)
filter := parseAffiliateRecordFilter(c, page, pageSize)
items, total, err := h.affiliateService.AdminListInviteRecords(c.Request.Context(), filter)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Paginated(c, items, total, filter.Page, filter.PageSize)
}
// ListRebateRecords returns all order-level affiliate rebate records.
// GET /api/v1/admin/affiliates/rebates
func (h *AffiliateHandler) ListRebateRecords(c *gin.Context) {
page, pageSize := response.ParsePagination(c)
filter := parseAffiliateRecordFilter(c, page, pageSize)
items, total, err := h.affiliateService.AdminListRebateRecords(c.Request.Context(), filter)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Paginated(c, items, total, filter.Page, filter.PageSize)
}
// ListTransferRecords returns all affiliate quota-to-balance transfer records.
// GET /api/v1/admin/affiliates/transfers
func (h *AffiliateHandler) ListTransferRecords(c *gin.Context) {
page, pageSize := response.ParsePagination(c)
filter := parseAffiliateRecordFilter(c, page, pageSize)
items, total, err := h.affiliateService.AdminListTransferRecords(c.Request.Context(), filter)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Paginated(c, items, total, filter.Page, filter.PageSize)
}
func parseAffiliateRecordFilter(c *gin.Context, page, pageSize int) service.AffiliateRecordFilter {
filter := service.AffiliateRecordFilter{
Search: c.Query("search"),
Page: page,
PageSize: pageSize,
SortBy: c.Query("sort_by"),
SortDesc: c.Query("sort_order") != "asc",
}
if filter.PageSize > 100 {
filter.PageSize = 100
}
userTZ := c.Query("timezone")
if t := parseAffiliateRecordStartTime(c.Query("start_at"), userTZ); t != nil {
filter.StartAt = t
}
if t := parseAffiliateRecordEndTime(c.Query("end_at"), userTZ); t != nil {
filter.EndAt = t
}
return filter
}
func parseAffiliateRecordStartTime(raw string, userTZ string) *time.Time {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
if parsed, err := time.Parse(time.RFC3339, raw); err == nil {
return &parsed
}
if parsed, err := timezone.ParseInUserLocation("2006-01-02", raw, userTZ); err == nil {
return &parsed
}
return nil
}
func parseAffiliateRecordEndTime(raw string, userTZ string) *time.Time {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
if parsed, err := time.Parse(time.RFC3339, raw); err == nil {
return &parsed
}
if parsed, err := timezone.ParseInUserLocation("2006-01-02", raw, userTZ); err == nil {
end := parsed.AddDate(0, 0, 1).Add(-time.Nanosecond)
return &end
}
return nil
}