Files
order/dao/order_yearly_statistics_dao.go
2026-02-24 16:49:31 +08:00

279 lines
7.3 KiB
Go
Raw 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 dao
import (
"context"
"fmt"
"time"
"order/consts"
"order/model/entity"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/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
}