Files
ai_dianshang/server/internal/handler/admin_stats.go
2025-11-17 14:11:46 +08:00

558 lines
16 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"dianshang/internal/service"
"dianshang/pkg/logger"
"dianshang/pkg/response"
"time"
"github.com/gin-gonic/gin"
)
// AdminStatsHandler 管理后台数据统计处理器
type AdminStatsHandler struct {
orderService *service.OrderService
userService *service.UserService
productService *service.ProductService
refundService *service.RefundService
}
// NewAdminStatsHandler 创建管理后台数据统计处理器
func NewAdminStatsHandler(orderService *service.OrderService, userService *service.UserService, productService *service.ProductService, refundService *service.RefundService) *AdminStatsHandler {
return &AdminStatsHandler{
orderService: orderService,
userService: userService,
productService: productService,
refundService: refundService,
}
}
// GetDashboardStats 获取仪表盘统计数据
func (h *AdminStatsHandler) GetDashboardStats(c *gin.Context) {
// 获取今日统计
today := time.Now().Format("2006-01-02")
// 获取昨日统计用于对比
yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
// 获取本月统计
thisMonth := time.Now().Format("2006-01")
// 获取上月统计用于对比
lastMonth := time.Now().AddDate(0, -1, 0).Format("2006-01")
// 今日订单统计
todayOrderStats, err := h.orderService.GetOrderStatisticsWithDateRange(today, today)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取今日订单统计失败")
return
}
// 昨日订单统计
yesterdayOrderStats, err := h.orderService.GetOrderStatisticsWithDateRange(yesterday, yesterday)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取昨日订单统计失败")
return
}
// 本月订单统计
thisMonthOrderStats, err := h.orderService.GetOrderStatisticsWithDateRange(thisMonth+"-01", today)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取本月订单统计失败")
return
}
// 上月订单统计
lastMonthStart := time.Now().AddDate(0, -1, 0)
lastMonthEnd := time.Date(lastMonthStart.Year(), lastMonthStart.Month()+1, 0, 0, 0, 0, 0, lastMonthStart.Location())
lastMonthOrderStats, err := h.orderService.GetOrderStatisticsWithDateRange(lastMonth+"-01", lastMonthEnd.Format("2006-01-02"))
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取上月订单统计失败")
return
}
// 今日用户统计
todayUserStats, err := h.userService.GetUserStatistics(today, today)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取今日用户统计失败")
return
}
// 昨日用户统计
yesterdayUserStats, err := h.userService.GetUserStatistics(yesterday, yesterday)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取昨日用户统计失败")
return
}
// 上月用户统计
lastMonthUserStats, err := h.userService.GetUserStatistics(lastMonth+"-01", lastMonthEnd.Format("2006-01-02"))
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取上月用户统计失败")
return
}
// 商品统计
productStats, err := h.productService.GetProductStatistics()
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取商品统计失败")
return
}
// 计算增长率的辅助函数
calculateGrowthRate := func(current, previous interface{}) float64 {
var currentVal, previousVal float64
switch v := current.(type) {
case int64:
currentVal = float64(v)
case float64:
currentVal = v
case int:
currentVal = float64(v)
default:
return 0
}
switch v := previous.(type) {
case int64:
previousVal = float64(v)
case float64:
previousVal = v
case int:
previousVal = float64(v)
default:
return 0
}
if previousVal == 0 {
if currentVal > 0 {
return 100 // 如果之前为0现在有值则为100%增长
}
return 0
}
return ((currentVal - previousVal) / previousVal) * 100
}
// 计算各项增长率
orderGrowthRate := calculateGrowthRate(todayOrderStats["total_orders"], yesterdayOrderStats["total_orders"])
revenueGrowthRate := calculateGrowthRate(todayOrderStats["total_amount"], yesterdayOrderStats["total_amount"])
userGrowthRate := calculateGrowthRate(todayUserStats["new_users"], yesterdayUserStats["new_users"])
// 月度增长率
monthlyOrderGrowthRate := calculateGrowthRate(thisMonthOrderStats["total_orders"], lastMonthOrderStats["total_orders"])
monthlyRevenueGrowthRate := calculateGrowthRate(thisMonthOrderStats["total_amount"], lastMonthOrderStats["total_amount"])
// 构建响应数据
dashboardStats := gin.H{
"overview": gin.H{
"total_users": gin.H{
"value": todayUserStats["total_users"],
"growth_rate": userGrowthRate,
"trend": getTrend(userGrowthRate),
},
"total_products": gin.H{
"value": productStats["total_products"],
"online": productStats["online_products"],
"offline": productStats["offline_products"],
"low_stock": productStats["low_stock_products"],
},
"total_orders": gin.H{
"value": thisMonthOrderStats["total_orders"],
"growth_rate": monthlyOrderGrowthRate,
"trend": getTrend(monthlyOrderGrowthRate),
},
"total_revenue": gin.H{
"value": thisMonthOrderStats["total_amount"],
"growth_rate": monthlyRevenueGrowthRate,
"trend": getTrend(monthlyRevenueGrowthRate),
},
},
"today_stats": gin.H{
"orders": gin.H{
"total": todayOrderStats["total_orders"],
"paid": todayOrderStats["paid_orders"],
"amount": todayOrderStats["total_amount"],
"paid_amount": todayOrderStats["paid_amount"],
"growth_rate": orderGrowthRate,
"trend": getTrend(orderGrowthRate),
},
"users": gin.H{
"new_users": todayUserStats["new_users"],
"active_users": todayUserStats["active_users"],
"growth_rate": userGrowthRate,
"trend": getTrend(userGrowthRate),
},
"revenue": gin.H{
"amount": todayOrderStats["total_amount"],
"paid_amount": todayOrderStats["paid_amount"],
"growth_rate": revenueGrowthRate,
"trend": getTrend(revenueGrowthRate),
},
},
"comparison": gin.H{
"yesterday": gin.H{
"orders": yesterdayOrderStats["total_orders"],
"amount": yesterdayOrderStats["total_amount"],
"new_users": yesterdayUserStats["new_users"],
},
"last_month": gin.H{
"orders": lastMonthOrderStats["total_orders"],
"amount": lastMonthOrderStats["total_amount"],
"new_users": lastMonthUserStats["new_users"],
},
},
"product_stats": productStats,
"update_time": time.Now().Format("2006-01-02 15:04:05"),
}
response.Success(c, dashboardStats)
}
// getTrend 根据增长率获取趋势标识
func getTrend(growthRate float64) string {
if growthRate > 0 {
return "up"
} else if growthRate < 0 {
return "down"
}
return "stable"
}
// GetOrderTrend 获取订单趋势
func (h *AdminStatsHandler) GetOrderTrend(c *gin.Context) {
days := c.DefaultQuery("days", "7")
var startDate string
switch days {
case "7":
startDate = time.Now().AddDate(0, 0, -7).Format("2006-01-02")
case "30":
startDate = time.Now().AddDate(0, 0, -30).Format("2006-01-02")
case "90":
startDate = time.Now().AddDate(0, 0, -90).Format("2006-01-02")
default:
startDate = time.Now().AddDate(0, 0, -7).Format("2006-01-02")
}
endDate := time.Now().Format("2006-01-02")
trend, err := h.orderService.GetDailyOrderStatisticsWithDateRange(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, trend)
}
// GetUserTrend 获取用户增长趋势
func (h *AdminStatsHandler) GetUserTrend(c *gin.Context) {
days := c.DefaultQuery("days", "7")
var startDate string
switch days {
case "7":
startDate = time.Now().AddDate(0, 0, -7).Format("2006-01-02")
case "30":
startDate = time.Now().AddDate(0, 0, -30).Format("2006-01-02")
case "90":
startDate = time.Now().AddDate(0, 0, -90).Format("2006-01-02")
default:
startDate = time.Now().AddDate(0, 0, -7).Format("2006-01-02")
}
endDate := time.Now().Format("2006-01-02")
trend, err := h.userService.GetDailyUserStatistics(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, trend)
}
// GetSalesRanking 获取销售排行
func (h *AdminStatsHandler) GetSalesRanking(c *gin.Context) {
rankType := c.DefaultQuery("type", "product") // product, category, user
limit := c.DefaultQuery("limit", "10")
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
var ranking interface{}
var err error
switch rankType {
case "product":
ranking, err = h.productService.GetProductSalesRanking(startDate, endDate, limit)
case "category":
ranking, err = h.productService.GetCategorySalesRanking(startDate, endDate, limit)
case "user":
ranking, err = h.userService.GetUserPurchaseRanking(startDate, endDate, limit)
default:
response.BadRequest(c, "不支持的排行类型")
return
}
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, ranking)
}
// GetRegionStats 获取地区统计
func (h *AdminStatsHandler) GetRegionStats(c *gin.Context) {
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
regionStats, err := h.orderService.GetRegionStatistics(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, regionStats)
}
// GetPaymentStats 获取支付方式统计
func (h *AdminStatsHandler) GetPaymentStats(c *gin.Context) {
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
paymentStats, err := h.orderService.GetPaymentMethodStatistics(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, paymentStats)
}
// GetRefundStats 获取退款统计
func (h *AdminStatsHandler) GetRefundStats(c *gin.Context) {
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
// 解析日期
startTime, err := time.Parse("2006-01-02", startDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "开始日期格式错误")
return
}
endTime, err := time.Parse("2006-01-02", endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "结束日期格式错误")
return
}
// 设置时间范围到一天的结束
endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
// 使用退款服务获取真实统计数据
refundStats, err := h.refundService.GetRefundStatistics(c.Request.Context(), startTime, endTime)
if err != nil {
logger.Error("获取退款统计失败", "error", err)
response.ErrorWithMessage(c, response.ERROR, "获取退款统计失败")
return
}
response.Success(c, refundStats)
}
// GetRealTimeStats 获取实时统计
func (h *AdminStatsHandler) GetRealTimeStats(c *gin.Context) {
// 获取今日实时数据
today := time.Now().Format("2006-01-02")
// 今日订单数
todayOrders, err := h.orderService.GetOrderStatisticsWithDateRange(today, today)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取今日订单统计失败")
return
}
// 今日新增用户
todayUsers, err := h.userService.GetUserStatistics(today, today)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取今日用户统计失败")
return
}
// 在线用户数这里简化处理实际应该从Redis或其他缓存中获取
onlineUsers := 0
// 待处理订单数
pendingOrders, err := h.orderService.GetPendingOrdersCount()
if err != nil {
response.ErrorWithMessage(c, response.ERROR, "获取待处理订单数失败")
return
}
realTimeStats := gin.H{
"today_orders": todayOrders["total_orders"],
"today_amount": todayOrders["total_amount"],
"today_new_users": todayUsers["new_users"],
"online_users": onlineUsers,
"pending_orders": pendingOrders,
"update_time": time.Now().Format("2006-01-02 15:04:05"),
}
response.Success(c, realTimeStats)
}
// GetUserGrowthTrend 获取用户增长趋势详细数据
func (h *AdminStatsHandler) GetUserGrowthTrend(c *gin.Context) {
days := c.DefaultQuery("days", "30")
var daysInt int
switch days {
case "7":
daysInt = 7
case "30":
daysInt = 30
case "90":
daysInt = 90
default:
daysInt = 30
}
trend, err := h.userService.GetUserGrowthTrend(daysInt)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, trend)
}
// GetUserActivityAnalysis 获取用户活跃度分析
func (h *AdminStatsHandler) GetUserActivityAnalysis(c *gin.Context) {
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
analysis, err := h.userService.GetUserActivityAnalysis(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, analysis)
}
// GetUserRetentionRate 获取用户留存率
func (h *AdminStatsHandler) GetUserRetentionRate(c *gin.Context) {
days := c.DefaultQuery("days", "30")
var daysInt int
switch days {
case "7":
daysInt = 7
case "30":
daysInt = 30
case "90":
daysInt = 90
default:
daysInt = 30
}
retention, err := h.userService.GetUserRetentionRate(daysInt)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, retention)
}
// GetUserLevelDistribution 获取用户等级分布
func (h *AdminStatsHandler) GetUserLevelDistribution(c *gin.Context) {
distribution, err := h.userService.GetUserLevelDistribution()
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, distribution)
}
// GetUserGeographicDistribution 获取用户地域分布
func (h *AdminStatsHandler) GetUserGeographicDistribution(c *gin.Context) {
distribution, err := h.userService.GetUserGeographicDistribution()
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, distribution)
}
// GetUserAgeDistribution 获取用户年龄分布
func (h *AdminStatsHandler) GetUserAgeDistribution(c *gin.Context) {
distribution, err := h.userService.GetUserAgeDistribution()
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, distribution)
}
// GetUserEngagementMetrics 获取用户参与度指标
func (h *AdminStatsHandler) GetUserEngagementMetrics(c *gin.Context) {
startDate := c.Query("start_date")
endDate := c.Query("end_date")
// 如果没有提供日期默认查询最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
metrics, err := h.userService.GetUserEngagementMetrics(startDate, endDate)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, metrics)
}