This commit is contained in:
2026-02-01 19:07:50 -08:00
parent af5231747a
commit 5b238919f5
7 changed files with 231 additions and 40 deletions
@@ -2,9 +2,9 @@ package user
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
@@ -85,17 +85,32 @@ func (l *GetAgentRealtimeLogic) GetAgentRealtime(req *types.GetAgentRealtimeRequ
link, err := client.CreateShortLink(l.ctx, kuttReq)
if err != nil {
l.Errorw("Failed to fetch Kutt stats",
l.Errorw("Failed to create/fetch Kutt link",
logger.Field("error", err.Error()),
logger.Field("user_id", u.Id),
logger.Field("target", target))
// Return 0 on error, don't block the UI
return &types.GetAgentRealtimeResponse{
Total: 0,
Total: 0,
GrowthRate: "0%",
}, nil
}
// 6. Get paid user count
// 6. Get detailed stats for growth rate calculation
stats, err := client.GetLinkStats(l.ctx, link.ID)
var growthRate string
if err != nil {
l.Errorw("Failed to fetch Kutt detailed stats, using basic count only",
logger.Field("error", err.Error()),
logger.Field("link_id", link.ID))
growthRate = "N/A"
} else {
// Calculate month-over-month growth rate
// lastYear.views is an array of 12 months, last element is current month, second-to-last is previous month
growthRate = calculateGrowthRate(stats.LastYear.Views)
}
// 7. Get paid user count
var paidCount int64
db := l.svcCtx.DB
// Count users invited by me who have paid orders
@@ -115,11 +130,16 @@ func (l *GetAgentRealtimeLogic) GetAgentRealtime(req *types.GetAgentRealtimeRequ
paidCount = 0
}
// 8. Calculate paid user growth rate (month-over-month)
paidGrowthRate := l.calculatePaidGrowthRate(u.Id)
return &types.GetAgentRealtimeResponse{
Total: int64(link.VisitCount),
Clicks: int64(link.VisitCount),
Views: int64(link.VisitCount),
PaidCount: paidCount,
Total: int64(link.VisitCount),
Clicks: int64(link.VisitCount),
Views: int64(link.VisitCount),
PaidCount: paidCount,
GrowthRate: growthRate,
PaidGrowthRate: paidGrowthRate,
}, nil
}
@@ -148,3 +168,78 @@ func (l *GetAgentRealtimeLogic) getDomain() string {
}
return l.svcCtx.Config.Kutt.Domain
}
// calculatePaidGrowthRate 计算付费用户的环比增长率
func (l *GetAgentRealtimeLogic) calculatePaidGrowthRate(userId int64) string {
db := l.svcCtx.DB
// 获取本月第一天和上月第一天
now := time.Now()
currentMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
lastMonthStart := currentMonthStart.AddDate(0, -1, 0)
// 查询本月付费用户数(本月有新订单的)
var currentMonthCount int64
err := db.Table("`order` o").
Joins("JOIN user u ON o.user_id = u.id").
Where("u.referer_id = ? AND o.status IN (?, ?) AND o.created_at >= ?",
userId, 2, 5, currentMonthStart).
Distinct("o.user_id").
Count(&currentMonthCount).Error
if err != nil {
l.Errorw("Failed to count current month paid users",
logger.Field("error", err.Error()),
logger.Field("user_id", userId))
return "N/A"
}
// 查询上月付费用户数
var lastMonthCount int64
err = db.Table("`order` o").
Joins("JOIN user u ON o.user_id = u.id").
Where("u.referer_id = ? AND o.status IN (?, ?) AND o.created_at >= ? AND o.created_at < ?",
userId, 2, 5, lastMonthStart, currentMonthStart).
Distinct("o.user_id").
Count(&lastMonthCount).Error
if err != nil {
l.Errorw("Failed to count last month paid users",
logger.Field("error", err.Error()),
logger.Field("user_id", userId))
return "N/A"
}
// 计算增长率
return calculateGrowthRate([]int{int(lastMonthCount), int(currentMonthCount)})
}
// calculateGrowthRate 计算环比增长率
// views: 月份数据数组,最后一个是本月,倒数第二个是上月
func calculateGrowthRate(views []int) string {
if len(views) < 2 {
return "N/A"
}
currentMonth := views[len(views)-1]
lastMonth := views[len(views)-2]
// 如果上月是0,无法计算百分比
if lastMonth == 0 {
if currentMonth == 0 {
return "0%"
}
return "+100%"
}
// 计算增长率
growth := float64(currentMonth-lastMonth) / float64(lastMonth) * 100
// 格式化输出
if growth > 0 {
return fmt.Sprintf("+%.1f%%", growth)
} else if growth < 0 {
return fmt.Sprintf("%.1f%%", growth)
}
return "0%"
}
@@ -111,7 +111,7 @@ func (l *GetInviteSalesLogic) GetInviteSales(req *types.GetInviteSalesRequest) (
}
list = append(list, types.InvitedUserSale{
Amount: order.Amount,
Amount: float64(order.Amount) / 100.0, // Convert cents to dollars
CreatedAt: order.CreatedAt,
UserEmail: email,
UserId: order.UserId,
@@ -2,6 +2,7 @@ package user
import (
"context"
"database/sql"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
@@ -36,21 +37,26 @@ func (l *GetUserInviteStatsLogic) GetUserInviteStats(req *types.GetUserInviteSta
}
userId := u.Id
// 2. 获取有效邀请数 (FriendlyCount): 被邀请用户中至少有1个已支付订单 (status=2或5)
var friendlyCount int64
// 2. 获取历史邀请佣金 (FriendlyCount): 所有被邀请用户产生订单的佣金总和
// 注意:这里复用了 friendly_count 字段名,实际含义是佣金总额
var totalCommission sql.NullInt64
err = l.svcCtx.DB.WithContext(l.ctx).
Table("user").
Where("referer_id = ? AND EXISTS (SELECT 1 FROM `order` o WHERE o.user_id = user.id AND o.status IN (?, ?))", userId, 2, 5).
Count(&friendlyCount).Error
Table("`order` o").
Select("COALESCE(SUM(o.commission), 0) as total").
Joins("JOIN user u ON o.user_id = u.id").
Where("u.referer_id = ? AND o.status IN (?, ?)", userId, 2, 5). // 只统计已支付和已完成的订单
Scan(&totalCommission).Error
if err != nil {
l.Errorw("[GetUserInviteStats] count friendly users failed",
l.Errorw("[GetUserInviteStats] sum commission failed",
logger.Field("error", err.Error()),
logger.Field("user_id", userId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError),
"count friendly users failed: %v", err.Error())
"sum commission failed: %v", err.Error())
}
friendlyCount := totalCommission.Int64
// 3. 获取历史邀请总数 (HistoryCount)
var historyCount int64
err = l.svcCtx.DB.WithContext(l.ctx).
+10 -8
View File
@@ -909,10 +909,12 @@ type GetGlobalConfigResponse struct {
type GetAgentRealtimeRequest struct{}
type GetAgentRealtimeResponse struct {
Total int64 `json:"total"` // 访问总人数
Clicks int64 `json:"clicks"` // 点击量
Views int64 `json:"views"` // 浏览量
PaidCount int64 `json:"paid_count"` // 付费数量
Total int64 `json:"total"` // 访问总人数
Clicks int64 `json:"clicks"` // 点击量
Views int64 `json:"views"` // 浏览量
PaidCount int64 `json:"paid_count"` // 付费数量
GrowthRate string `json:"growth_rate"` // 访问量环比增长率
PaidGrowthRate string `json:"paid_growth_rate"` // 付费用户环比增长率
}
type GetAgentDownloadsRequest struct{}
@@ -945,10 +947,10 @@ type GetInviteSalesResponse struct {
}
type InvitedUserSale struct {
Amount int64 `json:"amount"`
CreatedAt int64 `json:"created_at"`
UserEmail string `json:"user_email"`
UserId int64 `json:"user_id"`
Amount float64 `json:"amount"`
CreatedAt int64 `json:"created_at"`
UserEmail string `json:"user_email"`
UserId int64 `json:"user_id"`
}
type GetLoginLogRequest struct {