Files
order/service/order_statistics.go
2025-12-12 16:20:47 +08:00

440 lines
15 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 service
import (
"context"
"fmt"
"time"
"order/dao"
"order/model/dto"
"github.com/gogf/gf/v2/frame/g"
)
// OrderStatistics 订单统计服务
type orderStatistics struct{}
// OrderStatistics 订单统计服务实例
var OrderStatistics = new(orderStatistics)
// GenerateDailyStatistics 生成日统计数据
func (s *orderStatistics) GenerateDailyStatistics(ctx context.Context, tenantID int64, date time.Time, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %s 的日统计数据", tenantID, date.Format("2006-01-02"))
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderDailyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, date)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %s 的日统计数据已存在,跳过生成", tenantID, date.Format("2006-01-02"))
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderDailyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, date)
if err != nil {
return fmt.Errorf("生成日统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderDailyStatisticsDAOInstance.Update(ctx, statistics)
if err != nil {
return fmt.Errorf("保存日统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %s 的日统计数据生成成功", tenantID, date.Format("2006-01-02"))
return nil
}
// GenerateMonthlyStatistics 生成月统计数据
func (s *orderStatistics) GenerateMonthlyStatistics(ctx context.Context, tenantID int64, year int, month int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年%d月 的月统计数据", tenantID, year, month)
// 计算月份的起止日期
startDate := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderMonthlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年%d月 的月统计数据已存在,跳过生成", tenantID, year, month)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderMonthlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year, month)
if err != nil {
return fmt.Errorf("生成月统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderMonthlyStatisticsDAOInstance.Update(ctx, statistics)
if err != nil {
return fmt.Errorf("保存月统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年%d月 的月统计数据生成成功", tenantID, year, month)
return nil
}
// GenerateQuarterlyStatistics 生成季度统计数据
func (s *orderStatistics) GenerateQuarterlyStatistics(ctx context.Context, tenantID int64, year int, quarter int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年第%d季度 的统计数据", tenantID, year, quarter)
// 计算季度的起止月份
startMonth := (quarter-1)*3 + 1
startDate := time.Date(year, time.Month(startMonth), 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderQuarterlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年第%d季度 的统计数据已存在,跳过生成", tenantID, year, quarter)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderQuarterlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year, quarter)
if err != nil {
return fmt.Errorf("生成季度统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderQuarterlyStatisticsDAOInstance.Save(ctx, statistics)
if err != nil {
return fmt.Errorf("保存季度统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年第%d季度 的统计数据生成成功", tenantID, year, quarter)
return nil
}
// GenerateYearlyStatistics 生成年统计数据
func (s *orderStatistics) GenerateYearlyStatistics(ctx context.Context, tenantID int64, year int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年 的年统计数据", tenantID, year)
// 计算年的起止日期
startDate := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderYearlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年 的年统计数据已存在,跳过生成", tenantID, year)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderYearlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year)
if err != nil {
return fmt.Errorf("生成年统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderYearlyStatisticsDAOInstance.Save(ctx, statistics)
if err != nil {
return fmt.Errorf("保存年统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年 的年统计数据生成成功", tenantID, year)
return nil
}
// GetStatistics 获取统计数据
func (s *orderStatistics) GetStatistics(ctx context.Context, req *dto.GetOrderStatisticsReq) (*dto.GetOrderStatisticsRes, error) {
reportDate, err := time.Parse("2006-01-02", req.StartDate)
if err != nil {
return nil, fmt.Errorf("日期格式错误: %v", err)
}
var result *dto.OrderStatisticsDetail
// 根据统计类型调用不同的DAO
switch req.ReportType {
case "daily":
statistics, err := dao.OrderDailyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取日统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "daily",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "monthly":
statistics, err := dao.OrderMonthlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取月统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "monthly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "quarterly":
statistics, err := dao.OrderQuarterlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取季度统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "quarterly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "yearly":
statistics, err := dao.OrderYearlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取年度统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "yearly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
default:
return nil, fmt.Errorf("不支持的统计类型: %s", req.ReportType)
}
return &dto.GetOrderStatisticsRes{
Statistics: result,
}, nil
}
// GetStatisticsList 获取统计列表
func (s *orderStatistics) GetStatisticsList(ctx context.Context, req *dto.GetOrderStatisticsListReq) (*dto.GetOrderStatisticsListRes, error) {
// 设置默认分页参数
pageNum := req.PageNum
if pageNum <= 0 {
pageNum = 1
}
pageSize := req.PageSize
if pageSize <= 0 {
pageSize = 20
}
var startDate, endDate time.Time
var err error
if req.StartDate != "" {
startDate, err = time.Parse("2006-01-02", req.StartDate)
if err != nil {
return nil, fmt.Errorf("开始日期格式错误: %v", err)
}
}
if req.EndDate != "" {
endDate, err = time.Parse("2006-01-02", req.EndDate)
if err != nil {
return nil, fmt.Errorf("结束日期格式错误: %v", err)
}
// 设置为当天的结束时间
endDate = endDate.Add(24 * time.Hour).Add(-time.Second)
}
var result []*dto.OrderStatisticsDetail
var totalCount int64
// 根据统计类型调用不同的DAO
switch req.ReportType {
case "daily":
list, count, err := dao.OrderDailyStatisticsDAOInstance.GetListByTenant(ctx, req.TenantID, startDate, endDate, pageNum, pageSize)
if err != nil {
return nil, fmt.Errorf("获取日统计列表失败: %v", err)
}
totalCount = count
for _, item := range list {
result = append(result, &dto.OrderStatisticsDetail{
ReportType: "daily",
ReportDate: item.ReportDate,
Period: item.Period,
TotalOrders: item.TotalOrders,
CompletedOrders: item.CompletedOrders,
CancelledOrders: item.CancelledOrders,
PaidOrders: item.PaidOrders,
TotalAmount: item.TotalAmount,
PaidAmount: item.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: item.NetAmount,
AverageOrderValue: item.AverageOrderValue,
PaymentRate: item.PaymentRate,
CompletionRate: item.CompletionRate,
UniqueUsers: item.UniqueUsers,
NewUsers: item.NewUsers,
ReturningUsers: item.ReturningUsers,
TotalItems: item.TotalItems,
UniqueAssets: item.UniqueAssets,
TopAssetID: item.TopAssetID,
TopAssetName: item.TopAssetName,
TopAssetCount: item.TopAssetCount,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
})
}
case "monthly":
// 月度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
case "quarterly":
// 季度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
case "yearly":
// 年度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
default:
return nil, fmt.Errorf("不支持的统计类型: %s", req.ReportType)
}
return &dto.GetOrderStatisticsListRes{
List: result,
TotalCount: totalCount,
PageNum: pageNum,
PageSize: pageSize,
}, nil
}
// GenerateStatistics 生成统计数据
func (s *orderStatistics) GenerateStatistics(ctx context.Context, req *dto.GenerateOrderStatisticsReq) (*dto.GenerateOrderStatisticsRes, error) {
reportDate := time.Now()
if req.ReportDate != "" {
var err error
reportDate, err = time.Parse("2006-01-02", req.ReportDate)
if err != nil {
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: "日期格式错误请使用YYYY-MM-DD格式",
}, nil
}
}
var err error
switch req.ReportType {
case "daily":
err = s.GenerateDailyStatistics(ctx, req.TenantID, reportDate, req.Force)
case "monthly":
err = s.GenerateMonthlyStatistics(ctx, req.TenantID, reportDate.Year(), int(reportDate.Month()), req.Force)
case "quarterly":
quarter := (int(reportDate.Month())-1)/3 + 1
err = s.GenerateQuarterlyStatistics(ctx, req.TenantID, reportDate.Year(), quarter, req.Force)
case "yearly":
err = s.GenerateYearlyStatistics(ctx, req.TenantID, reportDate.Year(), req.Force)
default:
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: "不支持的统计类型",
}, nil
}
if err != nil {
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: fmt.Sprintf("生成统计数据失败: %v", err),
}, nil
}
return &dto.GenerateOrderStatisticsRes{
Success: true,
Message: "统计数据生成成功",
}, nil
}