package dao import ( "context" "fmt" "time" "order/consts" "order/model/entity" "gitea.com/red-future/common/beans" "gitea.com/red-future/common/db/mongo" "go.mongodb.org/mongo-driver/v2/bson" ) // OrderYearlyStatisticsDAO 订单年度统计DAO type OrderYearlyStatisticsDAO struct { } var OrderYearlyStatisticsDAOInstance = &OrderYearlyStatisticsDAO{} // GenerateStatistics 使用Go代码生成年度统计数据 func (dao *OrderYearlyStatisticsDAO) GenerateStatistics(ctx context.Context, tenantID int64, year int) (*entity.OrderYearlyStatistics, error) { // 设置时间范围 startDate := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local) endDate := startDate.AddDate(1, 0, 0) // 查询订单数据 filter := bson.M{ "tenantId": tenantID, "createdAt": bson.M{ "$gte": startDate, "$lt": endDate, }, } var orders []*entity.OrderBase err := mongo.DB().Find(ctx, filter, &orders, consts.OrderCollection) if err != nil { return nil, fmt.Errorf("查询订单数据失败: %v", err) } // 如果没有数据,创建空统计 if len(orders) == 0 { statistics := &entity.OrderYearlyStatistics{ MongoBaseDO: beans.MongoBaseDO{ TenantId: tenantID, CreatedAt: time.Now(), UpdatedAt: time.Now(), }, ReportDate: startDate, Period: startDate.Format("2006"), Year: year, } return statistics, nil } // 使用Go代码计算统计指标 totalOrders := int64(len(orders)) totalAmount := int64(0) completedOrders := int64(0) cancelledOrders := int64(0) paidOrders := int64(0) totalItems := int64(0) uniqueUsers := make(map[int64]bool) uniqueAssets := make(map[string]bool) assetCounts := make(map[string]int64) quarterlyOrders := make([]int64, 4) quarterlyAmounts := make([]int64, 4) monthlyOrders := make([]int64, 12) monthlyAmounts := make([]int64, 12) for _, order := range orders { // 计算总金额 totalAmount += order.TotalAmount // 注意:OrderBase结构体没有Status字段,状态统计需要通过其他方式获取 // 统计唯一用户 uniqueUsers[order.UserID] = true // 统计商品信息 if order.OrderItems != nil { totalItems += int64(len(order.OrderItems)) for _, item := range order.OrderItems { uniqueAssets[item.AssetID] = true assetCounts[item.AssetID]++ } } // 统计季度分布 quarter := (int(order.CreatedAt.Month())-1)/3 + 1 if quarter >= 1 && quarter <= 4 { quarterlyOrders[quarter-1]++ quarterlyAmounts[quarter-1] += order.TotalAmount } // 统计月度分布 month := int(order.CreatedAt.Month()) if month >= 1 && month <= 12 { monthlyOrders[month-1]++ monthlyAmounts[month-1] += order.TotalAmount } } // 计算业务指标 var averageOrderValue int64 if totalOrders > 0 { averageOrderValue = totalAmount / totalOrders } var paymentRate, completionRate float64 if totalOrders > 0 { paymentRate = float64(paidOrders) / float64(totalOrders) * 100 completionRate = float64(completedOrders) / float64(totalOrders) * 100 } // 获取热门资产 topAssetID, topAssetName, topAssetCount := dao.findTopAsset(assetCounts, orders) statistics := &entity.OrderYearlyStatistics{ MongoBaseDO: beans.MongoBaseDO{ TenantId: tenantID, CreatedAt: time.Now(), UpdatedAt: time.Now(), }, ReportDate: startDate, Period: startDate.Format("2006"), Year: year, TotalOrders: totalOrders, CompletedOrders: completedOrders, CancelledOrders: cancelledOrders, PaidOrders: paidOrders, TotalAmount: totalAmount, PaidAmount: totalAmount, NetAmount: totalAmount, AverageOrderValue: averageOrderValue, PaymentRate: paymentRate, CompletionRate: completionRate, UniqueUsers: int64(len(uniqueUsers)), NewUsers: 0, ReturningUsers: 0, TotalItems: totalItems, UniqueAssets: int64(len(uniqueAssets)), TopAssetID: topAssetID, TopAssetName: topAssetName, TopAssetCount: topAssetCount, QuarterlyOrders: quarterlyOrders, QuarterlyAmounts: quarterlyAmounts, PeakQuarter: dao.findPeakQuarter(quarterlyOrders), MonthlyOrders: monthlyOrders, MonthlyAmounts: monthlyAmounts, YearOverYearGrowth: dao.calculateYearOverYearGrowth(ctx, tenantID, year, totalOrders), } return statistics, nil } // findTopAsset 找出热门资产 func (dao *OrderYearlyStatisticsDAO) findTopAsset(assetCounts map[string]int64, orders []*entity.OrderBase) (string, string, int64) { if len(assetCounts) == 0 { return "", "", 0 } var topAssetID string var maxCount int64 for assetID, count := range assetCounts { if count > maxCount { maxCount = count topAssetID = assetID } } // 查找资产名称 var topAssetName string for _, order := range orders { if order.OrderItems != nil { for _, item := range order.OrderItems { if item.AssetID == topAssetID { topAssetName = item.AssetName break } } } if topAssetName != "" { break } } return topAssetID, topAssetName, maxCount } // findPeakQuarter 找出高峰季度 func (dao *OrderYearlyStatisticsDAO) findPeakQuarter(quarterlyOrders []int64) int { maxQuarter := 1 maxCount := int64(0) for i, count := range quarterlyOrders { if count > maxCount { maxCount = count maxQuarter = i + 1 } } return maxQuarter } // calculateYearOverYearGrowth 计算同比增长率 func (dao *OrderYearlyStatisticsDAO) calculateYearOverYearGrowth(ctx context.Context, tenantID int64, year int, currentOrders int64) float64 { // 查询去年同期的订单数据 lastYear := year - 1 lastYearStartDate := time.Date(lastYear, 1, 1, 0, 0, 0, 0, time.Local) lastYearEndDate := lastYearStartDate.AddDate(1, 0, 0) filter := bson.M{ "tenantId": tenantID, "createdAt": bson.M{ "$gte": lastYearStartDate, "$lt": lastYearEndDate, }, } var lastYearOrders []*entity.OrderBase err := mongo.DB().Find(ctx, filter, &lastYearOrders, consts.OrderCollection) if err != nil || len(lastYearOrders) == 0 { return 0.0 } lastYearOrderCount := int64(len(lastYearOrders)) if lastYearOrderCount == 0 { return 0.0 } // 计算同比增长率 growth := (float64(currentOrders) - float64(lastYearOrderCount)) / float64(lastYearOrderCount) * 100 return growth } // Save 保存年度统计数据 func (dao *OrderYearlyStatisticsDAO) Save(ctx context.Context, statistics *entity.OrderYearlyStatistics) error { _, err := mongo.DB().Insert(ctx, []interface{}{statistics}, consts.OrderYearlyStatisticsCollection) return err } // Update 更新年度统计数据 func (dao *OrderYearlyStatisticsDAO) Update(ctx context.Context, statistics *entity.OrderYearlyStatistics) error { filter := bson.M{ "tenantId": statistics.TenantId, "reportDate": statistics.ReportDate, } update := bson.M{ "$set": statistics, } _, err := mongo.DB().Update(ctx, filter, update, consts.OrderYearlyStatisticsCollection) return err } // GetByTenantAndDate 获取指定租户和日期的年度统计数据 func (dao *OrderYearlyStatisticsDAO) GetByTenantAndDate(ctx context.Context, tenantID int64, reportDate time.Time) (*entity.OrderYearlyStatistics, error) { var result entity.OrderYearlyStatistics filter := bson.M{ "tenantId": tenantID, "reportDate": reportDate, } err := mongo.DB().FindOne(ctx, filter, &result, consts.OrderYearlyStatisticsCollection) if err != nil { return nil, err } return &result, nil }