2744 lines
84 KiB
Go
2744 lines
84 KiB
Go
package statistics
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"go.uber.org/zap"
|
||
|
||
"tyapi-server/internal/domains/statistics/entities"
|
||
"tyapi-server/internal/domains/statistics/repositories"
|
||
"tyapi-server/internal/domains/statistics/services"
|
||
|
||
// 认证领域
|
||
certificationEntities "tyapi-server/internal/domains/certification/entities"
|
||
certificationEnums "tyapi-server/internal/domains/certification/enums"
|
||
certificationQueries "tyapi-server/internal/domains/certification/repositories/queries"
|
||
|
||
// 添加其他领域的仓储接口
|
||
apiRepos "tyapi-server/internal/domains/api/repositories"
|
||
certificationRepos "tyapi-server/internal/domains/certification/repositories"
|
||
financeRepos "tyapi-server/internal/domains/finance/repositories"
|
||
productRepos "tyapi-server/internal/domains/product/repositories"
|
||
productQueries "tyapi-server/internal/domains/product/repositories/queries"
|
||
userRepos "tyapi-server/internal/domains/user/repositories"
|
||
)
|
||
|
||
// StatisticsApplicationServiceImpl 统计应用服务实现
|
||
type StatisticsApplicationServiceImpl struct {
|
||
// 领域服务
|
||
aggregateService services.StatisticsAggregateService
|
||
calculationService services.StatisticsCalculationService
|
||
reportService services.StatisticsReportService
|
||
|
||
// 统计仓储
|
||
metricRepo repositories.StatisticsRepository
|
||
reportRepo repositories.StatisticsReportRepository
|
||
dashboardRepo repositories.StatisticsDashboardRepository
|
||
|
||
// 其他领域仓储
|
||
userRepo userRepos.UserRepository
|
||
enterpriseInfoRepo userRepos.EnterpriseInfoRepository
|
||
apiCallRepo apiRepos.ApiCallRepository
|
||
walletTransactionRepo financeRepos.WalletTransactionRepository
|
||
rechargeRecordRepo financeRepos.RechargeRecordRepository
|
||
productRepo productRepos.ProductRepository
|
||
certificationRepo certificationRepos.CertificationQueryRepository
|
||
|
||
// 日志
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// NewStatisticsApplicationService 创建统计应用服务
|
||
func NewStatisticsApplicationService(
|
||
aggregateService services.StatisticsAggregateService,
|
||
calculationService services.StatisticsCalculationService,
|
||
reportService services.StatisticsReportService,
|
||
metricRepo repositories.StatisticsRepository,
|
||
reportRepo repositories.StatisticsReportRepository,
|
||
dashboardRepo repositories.StatisticsDashboardRepository,
|
||
userRepo userRepos.UserRepository,
|
||
enterpriseInfoRepo userRepos.EnterpriseInfoRepository,
|
||
apiCallRepo apiRepos.ApiCallRepository,
|
||
walletTransactionRepo financeRepos.WalletTransactionRepository,
|
||
rechargeRecordRepo financeRepos.RechargeRecordRepository,
|
||
productRepo productRepos.ProductRepository,
|
||
certificationRepo certificationRepos.CertificationQueryRepository,
|
||
logger *zap.Logger,
|
||
) StatisticsApplicationService {
|
||
return &StatisticsApplicationServiceImpl{
|
||
aggregateService: aggregateService,
|
||
calculationService: calculationService,
|
||
reportService: reportService,
|
||
metricRepo: metricRepo,
|
||
reportRepo: reportRepo,
|
||
dashboardRepo: dashboardRepo,
|
||
userRepo: userRepo,
|
||
enterpriseInfoRepo: enterpriseInfoRepo,
|
||
apiCallRepo: apiCallRepo,
|
||
walletTransactionRepo: walletTransactionRepo,
|
||
rechargeRecordRepo: rechargeRecordRepo,
|
||
productRepo: productRepo,
|
||
certificationRepo: certificationRepo,
|
||
logger: logger,
|
||
}
|
||
}
|
||
|
||
// ================ 指标管理 ================
|
||
|
||
// CreateMetric 创建统计指标
|
||
func (s *StatisticsApplicationServiceImpl) CreateMetric(ctx context.Context, cmd *CreateMetricCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("创建指标命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 创建指标实体
|
||
metric, err := entities.NewStatisticsMetric(
|
||
cmd.MetricType,
|
||
cmd.MetricName,
|
||
cmd.Dimension,
|
||
cmd.Value,
|
||
cmd.Date,
|
||
)
|
||
if err != nil {
|
||
s.logger.Error("创建指标实体失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "创建指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 保存指标
|
||
err = s.metricRepo.Save(ctx, metric)
|
||
if err != nil {
|
||
s.logger.Error("保存指标失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "保存指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertMetricToDTO(metric)
|
||
|
||
s.logger.Info("指标创建成功", zap.String("metric_id", metric.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "指标创建成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// UpdateMetric 更新统计指标
|
||
func (s *StatisticsApplicationServiceImpl) UpdateMetric(ctx context.Context, cmd *UpdateMetricCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("更新指标命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取指标
|
||
metric, err := s.metricRepo.FindByID(ctx, cmd.ID)
|
||
if err != nil {
|
||
s.logger.Error("查询指标失败", zap.String("metric_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "查询指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 更新指标值
|
||
err = metric.UpdateValue(cmd.Value)
|
||
if err != nil {
|
||
s.logger.Error("更新指标值失败", zap.String("metric_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "更新指标值失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 保存更新
|
||
err = s.metricRepo.Update(ctx, metric)
|
||
if err != nil {
|
||
s.logger.Error("保存指标更新失败", zap.String("metric_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "保存指标更新失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertMetricToDTO(metric)
|
||
|
||
s.logger.Info("指标更新成功", zap.String("metric_id", metric.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "指标更新成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// DeleteMetric 删除统计指标
|
||
func (s *StatisticsApplicationServiceImpl) DeleteMetric(ctx context.Context, cmd *DeleteMetricCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if cmd.ID == "" {
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "指标ID不能为空",
|
||
Error: "指标ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 删除指标
|
||
err := s.metricRepo.Delete(ctx, cmd.ID)
|
||
if err != nil {
|
||
s.logger.Error("删除指标失败", zap.String("metric_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "删除指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
s.logger.Info("指标删除成功", zap.String("metric_id", cmd.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "指标删除成功",
|
||
}, nil
|
||
}
|
||
|
||
// GetMetric 获取单个指标
|
||
func (s *StatisticsApplicationServiceImpl) GetMetric(ctx context.Context, query *GetMetricQuery) (*QueryResponse, error) {
|
||
// 验证查询
|
||
if query.MetricID == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "指标ID不能为空",
|
||
Error: "指标ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 查询指标
|
||
metric, err := s.metricRepo.FindByID(ctx, query.MetricID)
|
||
if err != nil {
|
||
s.logger.Error("查询指标失败", zap.String("metric_id", query.MetricID), zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "查询指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertMetricToDTO(metric)
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// GetMetrics 获取指标列表
|
||
func (s *StatisticsApplicationServiceImpl) GetMetrics(ctx context.Context, query *GetMetricsQuery) (*ListResponse, error) {
|
||
// 设置默认值
|
||
if query.Limit <= 0 {
|
||
query.Limit = 20
|
||
}
|
||
if query.Limit > 1000 {
|
||
query.Limit = 1000
|
||
}
|
||
|
||
// 查询指标
|
||
var metrics []*entities.StatisticsMetric
|
||
var err error
|
||
|
||
if query.MetricType != "" && !query.StartDate.IsZero() && !query.EndDate.IsZero() {
|
||
metrics, err = s.metricRepo.FindByTypeAndDateRange(ctx, query.MetricType, query.StartDate, query.EndDate)
|
||
} else if query.MetricType != "" {
|
||
metrics, err = s.metricRepo.FindByType(ctx, query.MetricType, query.Limit, query.Offset)
|
||
} else {
|
||
return &ListResponse{
|
||
Success: false,
|
||
Message: "查询条件不完整",
|
||
Data: ListDataDTO{},
|
||
Error: "查询条件不完整",
|
||
}, nil
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("查询指标列表失败", zap.Error(err))
|
||
return &ListResponse{
|
||
Success: false,
|
||
Message: "查询指标列表失败",
|
||
Data: ListDataDTO{},
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
var dtos []interface{}
|
||
for _, metric := range metrics {
|
||
dtos = append(dtos, s.convertMetricToDTO(metric))
|
||
}
|
||
|
||
// 计算分页信息
|
||
total := int64(len(metrics))
|
||
|
||
return &ListResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: ListDataDTO{
|
||
Total: total,
|
||
Page: query.Offset/query.Limit + 1,
|
||
Size: query.Limit,
|
||
Items: dtos,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// ================ 实时统计 ================
|
||
|
||
// GetRealtimeMetrics 获取实时指标
|
||
func (s *StatisticsApplicationServiceImpl) GetRealtimeMetrics(ctx context.Context, query *GetRealtimeMetricsQuery) (*QueryResponse, error) {
|
||
// 验证查询
|
||
if query.MetricType == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "指标类型不能为空",
|
||
Error: "指标类型不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 获取实时指标
|
||
metrics, err := s.aggregateService.GetRealtimeMetrics(ctx, query.MetricType)
|
||
if err != nil {
|
||
s.logger.Error("获取实时指标失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取实时指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 构建响应
|
||
dto := &RealtimeMetricsDTO{
|
||
MetricType: query.MetricType,
|
||
Metrics: metrics,
|
||
Timestamp: time.Now(),
|
||
Metadata: map[string]interface{}{
|
||
"time_range": query.TimeRange,
|
||
"dimension": query.Dimension,
|
||
},
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取实时指标成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// UpdateRealtimeMetric 更新实时指标
|
||
func (s *StatisticsApplicationServiceImpl) UpdateRealtimeMetric(ctx context.Context, metricType, metricName string, value float64) error {
|
||
return s.aggregateService.UpdateRealtimeMetric(ctx, metricType, metricName, value)
|
||
}
|
||
|
||
// ================ 历史统计 ================
|
||
|
||
// GetHistoricalMetrics 获取历史指标
|
||
func (s *StatisticsApplicationServiceImpl) GetHistoricalMetrics(ctx context.Context, query *GetHistoricalMetricsQuery) (*QueryResponse, error) {
|
||
// 验证查询
|
||
if query.MetricType == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "指标类型不能为空",
|
||
Error: "指标类型不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 获取历史指标
|
||
var metrics []*entities.StatisticsMetric
|
||
var err error
|
||
|
||
if query.MetricName != "" {
|
||
metrics, err = s.metricRepo.FindByTypeNameAndDateRange(ctx, query.MetricType, query.MetricName, query.StartDate, query.EndDate)
|
||
} else {
|
||
metrics, err = s.metricRepo.FindByTypeAndDateRange(ctx, query.MetricType, query.StartDate, query.EndDate)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取历史指标失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取历史指标失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
var dataPoints []DataPointDTO
|
||
var total, sum float64
|
||
var count int64
|
||
var max, min float64
|
||
|
||
if len(metrics) > 0 {
|
||
max = metrics[0].Value
|
||
min = metrics[0].Value
|
||
}
|
||
|
||
for _, metric := range metrics {
|
||
dataPoints = append(dataPoints, DataPointDTO{
|
||
Date: metric.Date,
|
||
Value: metric.Value,
|
||
Label: metric.MetricName,
|
||
})
|
||
total += metric.Value
|
||
sum += metric.Value
|
||
count++
|
||
if metric.Value > max {
|
||
max = metric.Value
|
||
}
|
||
if metric.Value < min {
|
||
min = metric.Value
|
||
}
|
||
}
|
||
|
||
// 计算汇总信息
|
||
summary := MetricsSummaryDTO{
|
||
Total: total,
|
||
Average: sum / float64(count),
|
||
Max: max,
|
||
Min: min,
|
||
Count: count,
|
||
}
|
||
|
||
// 构建响应
|
||
dto := &HistoricalMetricsDTO{
|
||
MetricType: query.MetricType,
|
||
MetricName: query.MetricName,
|
||
Dimension: query.Dimension,
|
||
DataPoints: dataPoints,
|
||
Summary: summary,
|
||
Metadata: map[string]interface{}{
|
||
"period": query.Period,
|
||
"aggregate_by": query.AggregateBy,
|
||
"group_by": query.GroupBy,
|
||
},
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取历史指标成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// AggregateMetrics 聚合指标
|
||
func (s *StatisticsApplicationServiceImpl) AggregateMetrics(ctx context.Context, metricType, dimension string, startDate, endDate time.Time) error {
|
||
return s.aggregateService.AggregateHourlyMetrics(ctx, startDate)
|
||
}
|
||
|
||
// ================ 仪表板管理 ================
|
||
|
||
// CreateDashboard 创建仪表板
|
||
func (s *StatisticsApplicationServiceImpl) CreateDashboard(ctx context.Context, cmd *CreateDashboardCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("创建仪表板命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 创建仪表板实体
|
||
dashboard, err := entities.NewStatisticsDashboard(
|
||
cmd.Name,
|
||
cmd.Description,
|
||
cmd.UserRole,
|
||
cmd.CreatedBy,
|
||
)
|
||
if err != nil {
|
||
s.logger.Error("创建仪表板实体失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "创建仪表板失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 设置配置
|
||
if cmd.Layout != "" {
|
||
dashboard.UpdateLayout(cmd.Layout)
|
||
}
|
||
if cmd.Widgets != "" {
|
||
dashboard.UpdateWidgets(cmd.Widgets)
|
||
}
|
||
if cmd.Settings != "" {
|
||
dashboard.UpdateSettings(cmd.Settings)
|
||
}
|
||
if cmd.RefreshInterval > 0 {
|
||
dashboard.UpdateRefreshInterval(cmd.RefreshInterval)
|
||
}
|
||
if cmd.AccessLevel != "" {
|
||
dashboard.AccessLevel = cmd.AccessLevel
|
||
}
|
||
|
||
// 保存仪表板
|
||
err = s.dashboardRepo.Save(ctx, dashboard)
|
||
if err != nil {
|
||
s.logger.Error("保存仪表板失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "保存仪表板失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertDashboardToDTO(dashboard)
|
||
|
||
s.logger.Info("仪表板创建成功", zap.String("dashboard_id", dashboard.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "仪表板创建成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// GetDashboardData 获取仪表板数据
|
||
func (s *StatisticsApplicationServiceImpl) GetDashboardData(ctx context.Context, query *GetDashboardDataQuery) (*QueryResponse, error) {
|
||
// 验证查询
|
||
if query.UserRole == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "用户角色不能为空",
|
||
Error: "用户角色不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 设置默认时间范围
|
||
if query.StartDate.IsZero() || query.EndDate.IsZero() {
|
||
now := time.Now()
|
||
switch query.Period {
|
||
case "today":
|
||
query.StartDate = now.Truncate(24 * time.Hour)
|
||
query.EndDate = query.StartDate.Add(24 * time.Hour)
|
||
case "week":
|
||
query.StartDate = now.Truncate(24*time.Hour).AddDate(0, 0, -7)
|
||
query.EndDate = now
|
||
case "month":
|
||
query.StartDate = now.Truncate(24*time.Hour).AddDate(0, 0, -30)
|
||
query.EndDate = now
|
||
default:
|
||
query.StartDate = now.Truncate(24 * time.Hour)
|
||
query.EndDate = query.StartDate.Add(24 * time.Hour)
|
||
}
|
||
}
|
||
|
||
// 构建仪表板数据
|
||
dto := &DashboardDataDTO{}
|
||
|
||
// API调用统计
|
||
apiCallsTotal, _ := s.calculationService.CalculateTotal(ctx, "api_calls", "total_count", query.StartDate, query.EndDate)
|
||
apiCallsSuccess, _ := s.calculationService.CalculateTotal(ctx, "api_calls", "success_count", query.StartDate, query.EndDate)
|
||
apiCallsFailed, _ := s.calculationService.CalculateTotal(ctx, "api_calls", "failed_count", query.StartDate, query.EndDate)
|
||
avgResponseTime, _ := s.calculationService.CalculateAverage(ctx, "api_calls", "response_time", query.StartDate, query.EndDate)
|
||
|
||
dto.APICalls.TotalCount = int64(apiCallsTotal)
|
||
dto.APICalls.SuccessCount = int64(apiCallsSuccess)
|
||
dto.APICalls.FailedCount = int64(apiCallsFailed)
|
||
dto.APICalls.SuccessRate = s.calculateRate(apiCallsSuccess, apiCallsTotal)
|
||
dto.APICalls.AvgResponseTime = avgResponseTime
|
||
|
||
// 用户统计
|
||
usersTotal, _ := s.calculationService.CalculateTotal(ctx, "users", "total_count", query.StartDate, query.EndDate)
|
||
usersCertified, _ := s.calculationService.CalculateTotal(ctx, "users", "certified_count", query.StartDate, query.EndDate)
|
||
usersActive, _ := s.calculationService.CalculateTotal(ctx, "users", "active_count", query.StartDate, query.EndDate)
|
||
|
||
dto.Users.TotalCount = int64(usersTotal)
|
||
dto.Users.CertifiedCount = int64(usersCertified)
|
||
dto.Users.ActiveCount = int64(usersActive)
|
||
dto.Users.CertificationRate = s.calculateRate(usersCertified, usersTotal)
|
||
dto.Users.RetentionRate = s.calculateRate(usersActive, usersTotal)
|
||
|
||
// 财务统计
|
||
financeTotal, _ := s.calculationService.CalculateTotal(ctx, "finance", "total_amount", query.StartDate, query.EndDate)
|
||
rechargeAmount, _ := s.calculationService.CalculateTotal(ctx, "finance", "recharge_amount", query.StartDate, query.EndDate)
|
||
deductAmount, _ := s.calculationService.CalculateTotal(ctx, "finance", "deduct_amount", query.StartDate, query.EndDate)
|
||
|
||
dto.Finance.TotalAmount = financeTotal
|
||
dto.Finance.RechargeAmount = rechargeAmount
|
||
dto.Finance.DeductAmount = deductAmount
|
||
dto.Finance.NetAmount = rechargeAmount - deductAmount
|
||
|
||
// 设置时间信息
|
||
dto.Period.StartDate = query.StartDate.Format("2006-01-02")
|
||
dto.Period.EndDate = query.EndDate.Format("2006-01-02")
|
||
dto.Period.Period = query.Period
|
||
|
||
// 设置元数据
|
||
dto.Metadata.GeneratedAt = time.Now().Format("2006-01-02 15:04:05")
|
||
dto.Metadata.UserRole = query.UserRole
|
||
dto.Metadata.DataVersion = "1.0"
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取仪表板数据成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// ================ 报告管理 ================
|
||
|
||
// GenerateReport 生成报告
|
||
func (s *StatisticsApplicationServiceImpl) GenerateReport(ctx context.Context, cmd *GenerateReportCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("生成报告命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 生成报告
|
||
var report *entities.StatisticsReport
|
||
var err error
|
||
|
||
switch cmd.ReportType {
|
||
case "dashboard":
|
||
report, err = s.reportService.GenerateDashboardReport(ctx, cmd.UserRole, cmd.Period)
|
||
case "summary":
|
||
report, err = s.reportService.GenerateSummaryReport(ctx, cmd.Period, cmd.StartDate, cmd.EndDate)
|
||
case "detailed":
|
||
report, err = s.reportService.GenerateDetailedReport(ctx, cmd.Title, cmd.StartDate, cmd.EndDate, cmd.Filters)
|
||
default:
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "不支持的报告类型",
|
||
Error: "不支持的报告类型",
|
||
}, nil
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("生成报告失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "生成报告失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertReportToDTO(report)
|
||
|
||
s.logger.Info("报告生成成功", zap.String("report_id", report.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "报告生成成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// ================ 定时任务 ================
|
||
|
||
// ProcessHourlyAggregation 处理小时级聚合
|
||
func (s *StatisticsApplicationServiceImpl) ProcessHourlyAggregation(ctx context.Context, date time.Time) error {
|
||
return s.aggregateService.AggregateHourlyMetrics(ctx, date)
|
||
}
|
||
|
||
// ProcessDailyAggregation 处理日级聚合
|
||
func (s *StatisticsApplicationServiceImpl) ProcessDailyAggregation(ctx context.Context, date time.Time) error {
|
||
return s.aggregateService.AggregateDailyMetrics(ctx, date)
|
||
}
|
||
|
||
// ProcessWeeklyAggregation 处理周级聚合
|
||
func (s *StatisticsApplicationServiceImpl) ProcessWeeklyAggregation(ctx context.Context, date time.Time) error {
|
||
return s.aggregateService.AggregateWeeklyMetrics(ctx, date)
|
||
}
|
||
|
||
// ProcessMonthlyAggregation 处理月级聚合
|
||
func (s *StatisticsApplicationServiceImpl) ProcessMonthlyAggregation(ctx context.Context, date time.Time) error {
|
||
return s.aggregateService.AggregateMonthlyMetrics(ctx, date)
|
||
}
|
||
|
||
// CleanupExpiredData 清理过期数据
|
||
func (s *StatisticsApplicationServiceImpl) CleanupExpiredData(ctx context.Context) error {
|
||
return s.reportService.CleanupExpiredReports(ctx)
|
||
}
|
||
|
||
// ================ 辅助方法 ================
|
||
|
||
// convertMetricToDTO 转换指标实体为DTO
|
||
func (s *StatisticsApplicationServiceImpl) convertMetricToDTO(metric *entities.StatisticsMetric) *StatisticsMetricDTO {
|
||
return &StatisticsMetricDTO{
|
||
ID: metric.ID,
|
||
MetricType: metric.MetricType,
|
||
MetricName: metric.MetricName,
|
||
Dimension: metric.Dimension,
|
||
Value: metric.Value,
|
||
Metadata: metric.Metadata,
|
||
Date: metric.Date,
|
||
CreatedAt: metric.CreatedAt,
|
||
UpdatedAt: metric.UpdatedAt,
|
||
}
|
||
}
|
||
|
||
// convertReportToDTO 转换报告实体为DTO
|
||
func (s *StatisticsApplicationServiceImpl) convertReportToDTO(report *entities.StatisticsReport) *StatisticsReportDTO {
|
||
return &StatisticsReportDTO{
|
||
ID: report.ID,
|
||
ReportType: report.ReportType,
|
||
Title: report.Title,
|
||
Content: report.Content,
|
||
Period: report.Period,
|
||
UserRole: report.UserRole,
|
||
Status: report.Status,
|
||
GeneratedBy: report.GeneratedBy,
|
||
GeneratedAt: report.GeneratedAt,
|
||
ExpiresAt: report.ExpiresAt,
|
||
CreatedAt: report.CreatedAt,
|
||
UpdatedAt: report.UpdatedAt,
|
||
}
|
||
}
|
||
|
||
// convertDashboardToDTO 转换仪表板实体为DTO
|
||
func (s *StatisticsApplicationServiceImpl) convertDashboardToDTO(dashboard *entities.StatisticsDashboard) *StatisticsDashboardDTO {
|
||
return &StatisticsDashboardDTO{
|
||
ID: dashboard.ID,
|
||
Name: dashboard.Name,
|
||
Description: dashboard.Description,
|
||
UserRole: dashboard.UserRole,
|
||
IsDefault: dashboard.IsDefault,
|
||
IsActive: dashboard.IsActive,
|
||
Layout: dashboard.Layout,
|
||
Widgets: dashboard.Widgets,
|
||
Settings: dashboard.Settings,
|
||
RefreshInterval: dashboard.RefreshInterval,
|
||
CreatedBy: dashboard.CreatedBy,
|
||
AccessLevel: dashboard.AccessLevel,
|
||
CreatedAt: dashboard.CreatedAt,
|
||
UpdatedAt: dashboard.UpdatedAt,
|
||
}
|
||
}
|
||
|
||
// calculateRate 计算比率
|
||
func (s *StatisticsApplicationServiceImpl) calculateRate(numerator, denominator float64) float64 {
|
||
if denominator == 0 {
|
||
return 0
|
||
}
|
||
return (numerator / denominator) * 100
|
||
}
|
||
|
||
// ================ 其他方法的简化实现 ================
|
||
|
||
// UpdateDashboard 更新仪表板
|
||
func (s *StatisticsApplicationServiceImpl) UpdateDashboard(ctx context.Context, cmd *UpdateDashboardCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("更新仪表板命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取仪表板
|
||
dashboard, err := s.dashboardRepo.FindByID(ctx, cmd.ID)
|
||
if err != nil {
|
||
s.logger.Error("查询仪表板失败", zap.String("dashboard_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "查询仪表板失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 更新仪表板信息
|
||
if cmd.Name != "" {
|
||
// 直接设置字段值,因为实体没有UpdateName方法
|
||
dashboard.Name = cmd.Name
|
||
}
|
||
if cmd.Description != "" {
|
||
// 直接设置字段值,因为实体没有UpdateDescription方法
|
||
dashboard.Description = cmd.Description
|
||
}
|
||
if cmd.Layout != "" {
|
||
dashboard.UpdateLayout(cmd.Layout)
|
||
}
|
||
if cmd.Widgets != "" {
|
||
dashboard.UpdateWidgets(cmd.Widgets)
|
||
}
|
||
if cmd.Settings != "" {
|
||
dashboard.UpdateSettings(cmd.Settings)
|
||
}
|
||
if cmd.RefreshInterval > 0 {
|
||
dashboard.UpdateRefreshInterval(cmd.RefreshInterval)
|
||
}
|
||
if cmd.AccessLevel != "" {
|
||
dashboard.AccessLevel = cmd.AccessLevel
|
||
}
|
||
|
||
// 保存更新
|
||
err = s.dashboardRepo.Update(ctx, dashboard)
|
||
if err != nil {
|
||
s.logger.Error("保存仪表板更新失败", zap.String("dashboard_id", cmd.ID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "保存仪表板更新失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertDashboardToDTO(dashboard)
|
||
|
||
s.logger.Info("仪表板更新成功", zap.String("dashboard_id", cmd.ID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "仪表板更新成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// DeleteDashboard 删除仪表板
|
||
func (s *StatisticsApplicationServiceImpl) DeleteDashboard(ctx context.Context, cmd *DeleteDashboardCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if cmd.DashboardID == "" {
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "仪表板ID不能为空",
|
||
Error: "仪表板ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 检查仪表板是否存在
|
||
_, err := s.dashboardRepo.FindByID(ctx, cmd.DashboardID)
|
||
if err != nil {
|
||
s.logger.Error("查询仪表板失败", zap.String("dashboard_id", cmd.DashboardID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "仪表板不存在",
|
||
Error: "仪表板不存在",
|
||
}, nil
|
||
}
|
||
|
||
// 删除仪表板
|
||
err = s.dashboardRepo.Delete(ctx, cmd.DashboardID)
|
||
if err != nil {
|
||
s.logger.Error("删除仪表板失败", zap.String("dashboard_id", cmd.DashboardID), zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "删除仪表板失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
s.logger.Info("仪表板删除成功", zap.String("dashboard_id", cmd.DashboardID))
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "仪表板删除成功",
|
||
}, nil
|
||
}
|
||
|
||
// GetDashboard 获取单个仪表板
|
||
func (s *StatisticsApplicationServiceImpl) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*QueryResponse, error) {
|
||
// 验证查询
|
||
if query.DashboardID == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "仪表板ID不能为空",
|
||
Error: "仪表板ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 查询仪表板
|
||
dashboard, err := s.dashboardRepo.FindByID(ctx, query.DashboardID)
|
||
if err != nil {
|
||
s.logger.Error("查询仪表板失败", zap.String("dashboard_id", query.DashboardID), zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "查询仪表板失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
dto := s.convertDashboardToDTO(dashboard)
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: dto,
|
||
}, nil
|
||
}
|
||
|
||
// GetDashboards 获取仪表板列表
|
||
func (s *StatisticsApplicationServiceImpl) GetDashboards(ctx context.Context, query *GetDashboardsQuery) (*ListResponse, error) {
|
||
// 设置默认值
|
||
if query.Limit <= 0 {
|
||
query.Limit = 20
|
||
}
|
||
if query.Limit > 1000 {
|
||
query.Limit = 1000
|
||
}
|
||
|
||
// 查询仪表板列表
|
||
var dashboards []*entities.StatisticsDashboard
|
||
var err error
|
||
|
||
if query.UserRole != "" {
|
||
dashboards, err = s.dashboardRepo.FindByUserRole(ctx, query.UserRole, query.Limit, query.Offset)
|
||
} else if query.CreatedBy != "" {
|
||
dashboards, err = s.dashboardRepo.FindByUser(ctx, query.CreatedBy, query.Limit, query.Offset)
|
||
} else {
|
||
// 如果没有指定条件,返回空列表
|
||
dashboards = []*entities.StatisticsDashboard{}
|
||
err = nil
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("查询仪表板列表失败", zap.Error(err))
|
||
return &ListResponse{
|
||
Success: false,
|
||
Message: "查询仪表板列表失败",
|
||
Data: ListDataDTO{},
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 转换为DTO
|
||
var dtos []interface{}
|
||
for _, dashboard := range dashboards {
|
||
dtos = append(dtos, s.convertDashboardToDTO(dashboard))
|
||
}
|
||
|
||
// 计算分页信息
|
||
total := int64(len(dashboards))
|
||
|
||
return &ListResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: ListDataDTO{
|
||
Total: total,
|
||
Page: query.Offset/query.Limit + 1,
|
||
Size: query.Limit,
|
||
Items: dtos,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// SetDefaultDashboard 设置默认仪表板
|
||
func (s *StatisticsApplicationServiceImpl) SetDefaultDashboard(ctx context.Context, cmd *SetDefaultDashboardCommand) (*CommandResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "设置默认仪表板成功",
|
||
}, nil
|
||
}
|
||
|
||
// ActivateDashboard 激活仪表板
|
||
func (s *StatisticsApplicationServiceImpl) ActivateDashboard(ctx context.Context, cmd *ActivateDashboardCommand) (*CommandResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "激活仪表板成功",
|
||
}, nil
|
||
}
|
||
|
||
// DeactivateDashboard 停用仪表板
|
||
func (s *StatisticsApplicationServiceImpl) DeactivateDashboard(ctx context.Context, cmd *DeactivateDashboardCommand) (*CommandResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "停用仪表板成功",
|
||
}, nil
|
||
}
|
||
|
||
// GetReport 获取单个报告
|
||
func (s *StatisticsApplicationServiceImpl) GetReport(ctx context.Context, query *GetReportQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: map[string]interface{}{},
|
||
}, nil
|
||
}
|
||
|
||
// GetReports 获取报告列表
|
||
func (s *StatisticsApplicationServiceImpl) GetReports(ctx context.Context, query *GetReportsQuery) (*ListResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &ListResponse{
|
||
Success: true,
|
||
Message: "查询成功",
|
||
Data: ListDataDTO{
|
||
Total: 0,
|
||
Page: 1,
|
||
Size: query.Limit,
|
||
Items: []interface{}{},
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// DeleteReport 删除报告
|
||
func (s *StatisticsApplicationServiceImpl) DeleteReport(ctx context.Context, reportID string) (*CommandResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "报告删除成功",
|
||
}, nil
|
||
}
|
||
|
||
// CalculateGrowthRate 计算增长率
|
||
func (s *StatisticsApplicationServiceImpl) CalculateGrowthRate(ctx context.Context, query *CalculateGrowthRateQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "计算增长率成功",
|
||
Data: map[string]interface{}{"growth_rate": 0.0},
|
||
}, nil
|
||
}
|
||
|
||
// CalculateTrend 计算趋势
|
||
func (s *StatisticsApplicationServiceImpl) CalculateTrend(ctx context.Context, query *CalculateTrendQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "计算趋势成功",
|
||
Data: map[string]interface{}{"trend": "stable"},
|
||
}, nil
|
||
}
|
||
|
||
// CalculateCorrelation 计算相关性
|
||
func (s *StatisticsApplicationServiceImpl) CalculateCorrelation(ctx context.Context, query *CalculateCorrelationQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "计算相关性成功",
|
||
Data: map[string]interface{}{"correlation": 0.0},
|
||
}, nil
|
||
}
|
||
|
||
// CalculateMovingAverage 计算移动平均
|
||
func (s *StatisticsApplicationServiceImpl) CalculateMovingAverage(ctx context.Context, query *CalculateMovingAverageQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "计算移动平均成功",
|
||
Data: map[string]interface{}{"moving_averages": []float64{}},
|
||
}, nil
|
||
}
|
||
|
||
// CalculateSeasonality 计算季节性
|
||
func (s *StatisticsApplicationServiceImpl) CalculateSeasonality(ctx context.Context, query *CalculateSeasonalityQuery) (*QueryResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "计算季节性成功",
|
||
Data: map[string]interface{}{"seasonality": map[string]float64{}},
|
||
}, nil
|
||
}
|
||
|
||
// ExportData 导出数据
|
||
func (s *StatisticsApplicationServiceImpl) ExportData(ctx context.Context, cmd *ExportDataCommand) (*CommandResponse, error) {
|
||
// 简化实现,实际应该完整实现
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "数据导出成功",
|
||
Data: map[string]interface{}{"download_url": ""},
|
||
}, nil
|
||
}
|
||
|
||
// ================ 管理员专用方法 ================
|
||
|
||
// AdminGetSystemStatistics 管理员获取系统统计 - 简化版
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetSystemStatistics(ctx context.Context, period, startDate, endDate string) (*QueryResponse, error) {
|
||
// 解析时间参数
|
||
var startTime, endTime time.Time
|
||
var err error
|
||
|
||
if startDate != "" {
|
||
startTime, err = time.Parse("2006-01-02", startDate)
|
||
if err != nil {
|
||
s.logger.Error("开始日期格式错误", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "开始日期格式错误",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
if endDate != "" {
|
||
endTime, err = time.Parse("2006-01-02", endDate)
|
||
if err != nil {
|
||
s.logger.Error("结束日期格式错误", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "结束日期格式错误",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
// 获取系统统计数据,传递时间参数
|
||
systemStats, err := s.getAdminSystemStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取系统统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取系统统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 添加查询参数
|
||
systemStats["period"] = period
|
||
systemStats["start_date"] = startDate
|
||
systemStats["end_date"] = endDate
|
||
|
||
s.logger.Info("管理员获取系统统计", zap.String("period", period), zap.String("start_date", startDate), zap.String("end_date", endDate))
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取系统统计成功",
|
||
Data: systemStats,
|
||
Meta: map[string]interface{}{
|
||
"generated_at": time.Now(),
|
||
"period_type": period,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// AdminTriggerAggregation 管理员触发数据聚合
|
||
func (s *StatisticsApplicationServiceImpl) AdminTriggerAggregation(ctx context.Context, cmd *TriggerAggregationCommand) (*CommandResponse, error) {
|
||
// 验证命令
|
||
if err := cmd.Validate(); err != nil {
|
||
s.logger.Error("触发聚合命令验证失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "命令验证失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 根据周期类型执行不同的聚合任务
|
||
var err error
|
||
switch cmd.Period {
|
||
case "hourly":
|
||
err = s.ProcessHourlyAggregation(ctx, cmd.StartDate)
|
||
case "daily":
|
||
err = s.ProcessDailyAggregation(ctx, cmd.StartDate)
|
||
case "weekly":
|
||
err = s.ProcessWeeklyAggregation(ctx, cmd.StartDate)
|
||
case "monthly":
|
||
err = s.ProcessMonthlyAggregation(ctx, cmd.StartDate)
|
||
default:
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "不支持的聚合周期",
|
||
Error: "不支持的聚合周期",
|
||
}, nil
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("触发聚合失败", zap.Error(err))
|
||
return &CommandResponse{
|
||
Success: false,
|
||
Message: "触发聚合失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
s.logger.Info("管理员触发聚合成功",
|
||
zap.String("metric_type", cmd.MetricType),
|
||
zap.String("period", cmd.Period),
|
||
zap.String("triggered_by", cmd.TriggeredBy))
|
||
|
||
return &CommandResponse{
|
||
Success: true,
|
||
Message: "触发数据聚合成功",
|
||
Data: map[string]interface{}{
|
||
"metric_type": cmd.MetricType,
|
||
"period": cmd.Period,
|
||
"start_date": cmd.StartDate,
|
||
"end_date": cmd.EndDate,
|
||
"force": cmd.Force,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// ================ 公开和用户统计方法 ================
|
||
|
||
// GetPublicStatistics 获取公开统计信息
|
||
func (s *StatisticsApplicationServiceImpl) GetPublicStatistics(ctx context.Context) (*QueryResponse, error) {
|
||
// 获取公开的统计信息
|
||
publicStats := map[string]interface{}{
|
||
"total_users": 0,
|
||
"total_products": 0,
|
||
"total_categories": 0,
|
||
"total_api_calls": 0,
|
||
"system_uptime": "0天",
|
||
"last_updated": time.Now(),
|
||
}
|
||
|
||
// 实际实现中应该查询数据库获取真实数据
|
||
// 这里暂时返回模拟数据
|
||
s.logger.Info("获取公开统计信息")
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取公开统计信息成功",
|
||
Data: publicStats,
|
||
Meta: map[string]interface{}{
|
||
"generated_at": time.Now(),
|
||
"cache_ttl": 300, // 5分钟缓存
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// GetUserStatistics 获取用户统计信息
|
||
func (s *StatisticsApplicationServiceImpl) GetUserStatistics(ctx context.Context, userID string) (*QueryResponse, error) {
|
||
// 验证用户ID
|
||
if userID == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "用户ID不能为空",
|
||
Error: "用户ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户API调用统计
|
||
apiCalls, err := s.getUserApiCallsStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户API调用统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取API调用统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户消费统计
|
||
consumption, err := s.getUserConsumptionStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户消费统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取消费统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户充值统计
|
||
recharge, err := s.getUserRechargeStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户充值统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取充值统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 组装用户统计数据
|
||
userStats := map[string]interface{}{
|
||
"user_id": userID,
|
||
"api_calls": apiCalls,
|
||
"consumption": consumption,
|
||
"recharge": recharge,
|
||
"summary": map[string]interface{}{
|
||
"total_calls": apiCalls["total_calls"],
|
||
"total_consumed": consumption["total_amount"],
|
||
"total_recharged": recharge["total_amount"],
|
||
"balance": recharge["total_amount"].(float64) - consumption["total_amount"].(float64),
|
||
},
|
||
}
|
||
|
||
s.logger.Info("获取用户统计信息", zap.String("user_id", userID))
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取用户统计信息成功",
|
||
Data: userStats,
|
||
Meta: map[string]interface{}{
|
||
"generated_at": time.Now(),
|
||
"user_id": userID,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// ================ 简化版统计辅助方法 ================
|
||
|
||
// getUserApiCallsStats 获取用户API调用统计
|
||
func (s *StatisticsApplicationServiceImpl) getUserApiCallsStats(ctx context.Context, userID string) (map[string]interface{}, error) {
|
||
// 获取总调用次数
|
||
totalCalls, err := s.apiCallRepo.CountByUserId(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户API调用总数失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日调用次数
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayCalls, err := s.getApiCallsCountByDateRange(ctx, userID, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日API调用次数失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取本月调用次数
|
||
monthStart := time.Now().Truncate(24*time.Hour).AddDate(0, 0, -time.Now().Day()+1)
|
||
monthEnd := monthStart.AddDate(0, 1, 0)
|
||
monthCalls, err := s.getApiCallsCountByDateRange(ctx, userID, monthStart, monthEnd)
|
||
if err != nil {
|
||
s.logger.Error("获取本月API调用次数失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每日趋势(最近7天)
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
dailyTrend, err := s.getApiCallsDailyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用每日趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每月趋势(最近6个月)
|
||
endDate = time.Now()
|
||
startDate = endDate.AddDate(0, -6, 0)
|
||
monthlyTrend, err := s.getApiCallsMonthlyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用每月趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_calls": totalCalls,
|
||
"today_calls": todayCalls,
|
||
"this_month_calls": monthCalls,
|
||
"daily_trend": dailyTrend,
|
||
"monthly_trend": monthlyTrend,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getUserConsumptionStats 获取用户消费统计
|
||
func (s *StatisticsApplicationServiceImpl) getUserConsumptionStats(ctx context.Context, userID string) (map[string]interface{}, error) {
|
||
// 获取总消费金额
|
||
totalAmount, err := s.getTotalWalletTransactionAmount(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户总消费金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日消费金额
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayAmount, err := s.getWalletTransactionsByDateRange(ctx, userID, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日消费金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取本月消费金额
|
||
monthStart := time.Now().Truncate(24*time.Hour).AddDate(0, 0, -time.Now().Day()+1)
|
||
monthEnd := monthStart.AddDate(0, 1, 0)
|
||
monthAmount, err := s.getWalletTransactionsByDateRange(ctx, userID, monthStart, monthEnd)
|
||
if err != nil {
|
||
s.logger.Error("获取本月消费金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每日趋势(最近7天)
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
dailyTrend, err := s.getConsumptionDailyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取消费每日趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每月趋势(最近6个月)
|
||
endDate = time.Now()
|
||
startDate = endDate.AddDate(0, -6, 0)
|
||
monthlyTrend, err := s.getConsumptionMonthlyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取消费每月趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_amount": totalAmount,
|
||
"today_amount": todayAmount,
|
||
"this_month_amount": monthAmount,
|
||
"daily_trend": dailyTrend,
|
||
"monthly_trend": monthlyTrend,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getUserRechargeStats 获取用户充值统计
|
||
func (s *StatisticsApplicationServiceImpl) getUserRechargeStats(ctx context.Context, userID string) (map[string]interface{}, error) {
|
||
// 获取总充值金额
|
||
totalAmount, err := s.getTotalRechargeAmount(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户总充值金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日充值金额
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayAmount, err := s.getRechargeRecordsByDateRange(ctx, userID, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日充值金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取本月充值金额
|
||
monthStart := time.Now().Truncate(24*time.Hour).AddDate(0, 0, -time.Now().Day()+1)
|
||
monthEnd := monthStart.AddDate(0, 1, 0)
|
||
monthAmount, err := s.getRechargeRecordsByDateRange(ctx, userID, monthStart, monthEnd)
|
||
if err != nil {
|
||
s.logger.Error("获取本月充值金额失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每日趋势(最近7天)
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
dailyTrend, err := s.getRechargeDailyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取充值每日趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每月趋势(最近6个月)
|
||
endDate = time.Now()
|
||
startDate = endDate.AddDate(0, -6, 0)
|
||
monthlyTrend, err := s.getRechargeMonthlyTrend(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取充值每月趋势失败", zap.String("user_id", userID), zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_amount": totalAmount,
|
||
"today_amount": todayAmount,
|
||
"this_month_amount": monthAmount,
|
||
"daily_trend": dailyTrend,
|
||
"monthly_trend": monthlyTrend,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getAdminSystemStats 获取管理员系统统计
|
||
func (s *StatisticsApplicationServiceImpl) getAdminSystemStats(ctx context.Context, period string, startTime, endTime time.Time) (map[string]interface{}, error) {
|
||
// 获取用户统计
|
||
userStats, err := s.getUserStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取用户统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取认证统计
|
||
certificationStats, err := s.getCertificationStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取认证统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取API调用统计
|
||
apiCallStats, err := s.getSystemApiCallStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取财务统计
|
||
financeStats, err := s.getSystemFinanceStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取财务统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"users": userStats,
|
||
"certification": certificationStats,
|
||
"api_calls": apiCallStats,
|
||
"finance": financeStats,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// AdminGetUserStatistics 管理员获取单个用户统计
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetUserStatistics(ctx context.Context, userID string) (*QueryResponse, error) {
|
||
// 验证用户ID
|
||
if userID == "" {
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "用户ID不能为空",
|
||
Error: "用户ID不能为空",
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户API调用统计
|
||
apiCalls, err := s.getUserApiCallsStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户API调用统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取API调用统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户消费统计
|
||
consumption, err := s.getUserConsumptionStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户消费统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取消费统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 获取用户充值统计
|
||
recharge, err := s.getUserRechargeStats(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取用户充值统计失败", zap.Error(err))
|
||
return &QueryResponse{
|
||
Success: false,
|
||
Message: "获取充值统计失败",
|
||
Error: err.Error(),
|
||
}, nil
|
||
}
|
||
|
||
// 组装用户统计数据
|
||
userStats := map[string]interface{}{
|
||
"user_id": userID,
|
||
"api_calls": apiCalls,
|
||
"consumption": consumption,
|
||
"recharge": recharge,
|
||
"summary": map[string]interface{}{
|
||
"total_calls": apiCalls["total_calls"],
|
||
"total_consumed": consumption["total_amount"],
|
||
"total_recharged": recharge["total_amount"],
|
||
"balance": recharge["total_amount"].(float64) - consumption["total_amount"].(float64),
|
||
},
|
||
}
|
||
|
||
s.logger.Info("管理员获取用户统计", zap.String("user_id", userID))
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取用户统计成功",
|
||
Data: userStats,
|
||
Meta: map[string]interface{}{
|
||
"generated_at": time.Now(),
|
||
"user_id": userID,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// ================ 统计查询辅助方法 ================
|
||
|
||
// getApiCallsCountByDateRange 获取指定日期范围内的API调用次数
|
||
func (s *StatisticsApplicationServiceImpl) getApiCallsCountByDateRange(ctx context.Context, userID string, startDate, endDate time.Time) (int64, error) {
|
||
return s.apiCallRepo.CountByUserIdAndDateRange(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getApiCallsDailyTrend 获取API调用每日趋势
|
||
func (s *StatisticsApplicationServiceImpl) getApiCallsDailyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.apiCallRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getApiCallsMonthlyTrend 获取API调用每月趋势
|
||
func (s *StatisticsApplicationServiceImpl) getApiCallsMonthlyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.apiCallRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// ================ 更多统计查询辅助方法 ================
|
||
|
||
// getTotalWalletTransactionAmount 获取用户总钱包交易金额
|
||
func (s *StatisticsApplicationServiceImpl) getTotalWalletTransactionAmount(ctx context.Context, userID string) (float64, error) {
|
||
return s.walletTransactionRepo.GetTotalAmountByUserId(ctx, userID)
|
||
}
|
||
|
||
// getTotalRechargeAmount 获取用户总充值金额
|
||
func (s *StatisticsApplicationServiceImpl) getTotalRechargeAmount(ctx context.Context, userID string) (float64, error) {
|
||
return s.rechargeRecordRepo.GetTotalAmountByUserId(ctx, userID)
|
||
}
|
||
|
||
// getConsumptionDailyTrend 获取消费每日趋势
|
||
func (s *StatisticsApplicationServiceImpl) getConsumptionDailyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.walletTransactionRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getConsumptionMonthlyTrend 获取消费每月趋势
|
||
func (s *StatisticsApplicationServiceImpl) getConsumptionMonthlyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.walletTransactionRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getRechargeDailyTrend 获取充值每日趋势
|
||
func (s *StatisticsApplicationServiceImpl) getRechargeDailyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.rechargeRecordRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getRechargeMonthlyTrend 获取充值每月趋势
|
||
func (s *StatisticsApplicationServiceImpl) getRechargeMonthlyTrend(ctx context.Context, userID string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||
return s.rechargeRecordRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// getUserStats 获取用户统计
|
||
func (s *StatisticsApplicationServiceImpl) getUserStats(ctx context.Context, period string, startTime, endTime time.Time) (map[string]interface{}, error) {
|
||
// 获取系统用户统计信息
|
||
userStats, err := s.userRepo.GetSystemUserStats(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取用户统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 根据时间范围获取趋势数据
|
||
var trendData []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
trendData, err = s.userRepo.GetSystemDailyUserStats(ctx, startTime, endTime)
|
||
} else if period == "month" {
|
||
trendData, err = s.userRepo.GetSystemMonthlyUserStats(ctx, startTime, endTime)
|
||
}
|
||
if err != nil {
|
||
s.logger.Error("获取用户趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 默认获取最近7天的数据
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
trendData, err = s.userRepo.GetSystemDailyUserStats(ctx, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取用户每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 计算时间范围内的新增用户数
|
||
var newInRange int64
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
rangeStats, err := s.userRepo.GetSystemUserStatsByDateRange(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取时间范围内用户统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
newInRange = rangeStats.TodayRegistrations
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_users": userStats.TotalUsers,
|
||
"new_today": userStats.TodayRegistrations,
|
||
"new_in_range": newInRange,
|
||
"daily_trend": trendData,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getCertificationStats 获取认证统计
|
||
func (s *StatisticsApplicationServiceImpl) getCertificationStats(ctx context.Context, period string, startTime, endTime time.Time) (map[string]interface{}, error) {
|
||
// 获取系统用户统计信息
|
||
userStats, err := s.userRepo.GetSystemUserStats(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取用户统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 计算认证成功率
|
||
var successRate float64
|
||
if userStats.TotalUsers > 0 {
|
||
successRate = float64(userStats.CertifiedUsers) / float64(userStats.TotalUsers)
|
||
}
|
||
|
||
// 根据时间范围获取趋势数据
|
||
var trendData []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
trendData, err = s.userRepo.GetSystemDailyUserStats(ctx, startTime, endTime)
|
||
} else if period == "month" {
|
||
trendData, err = s.userRepo.GetSystemMonthlyUserStats(ctx, startTime, endTime)
|
||
}
|
||
if err != nil {
|
||
s.logger.Error("获取认证趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 默认获取最近7天的数据
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
trendData, err = s.userRepo.GetSystemDailyUserStats(ctx, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取认证每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_certified": userStats.CertifiedUsers,
|
||
"certified_today": userStats.TodayRegistrations, // 今日注册的用户
|
||
"success_rate": successRate,
|
||
"daily_trend": trendData,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getSystemApiCallStats 获取系统API调用统计
|
||
func (s *StatisticsApplicationServiceImpl) getSystemApiCallStats(ctx context.Context, period string, startTime, endTime time.Time) (map[string]interface{}, error) {
|
||
// 获取系统总API调用次数
|
||
totalCalls, err := s.apiCallRepo.GetSystemTotalCalls(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取系统总API调用次数失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日API调用次数
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayCalls, err := s.apiCallRepo.GetSystemCallsByDateRange(ctx, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日API调用次数失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 根据时间范围获取趋势数据
|
||
var trendData []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
trendData, err = s.apiCallRepo.GetSystemDailyStats(ctx, startTime, endTime)
|
||
} else if period == "month" {
|
||
trendData, err = s.apiCallRepo.GetSystemMonthlyStats(ctx, startTime, endTime)
|
||
}
|
||
if err != nil {
|
||
s.logger.Error("获取API调用趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 默认获取最近7天的数据
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
trendData, err = s.apiCallRepo.GetSystemDailyStats(ctx, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_calls": totalCalls,
|
||
"calls_today": todayCalls,
|
||
"daily_trend": trendData,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// getSystemFinanceStats 获取系统财务统计
|
||
func (s *StatisticsApplicationServiceImpl) getSystemFinanceStats(ctx context.Context, period string, startTime, endTime time.Time) (map[string]interface{}, error) {
|
||
// 获取系统总消费金额
|
||
totalConsumption, err := s.walletTransactionRepo.GetSystemTotalAmount(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取系统总消费金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取系统总充值金额
|
||
totalRecharge, err := s.rechargeRecordRepo.GetSystemTotalAmount(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取系统总充值金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日消费金额
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayConsumption, err := s.walletTransactionRepo.GetSystemAmountByDateRange(ctx, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日消费金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日充值金额
|
||
todayRecharge, err := s.rechargeRecordRepo.GetSystemAmountByDateRange(ctx, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日充值金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 根据时间范围获取趋势数据
|
||
var trendData []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
// 获取消费趋势
|
||
consumptionTrend, err := s.walletTransactionRepo.GetSystemDailyStats(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取消费趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
// 获取充值趋势
|
||
rechargeTrend, err := s.rechargeRecordRepo.GetSystemDailyStats(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取充值趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
// 合并趋势数据
|
||
trendData = s.mergeFinanceTrends(consumptionTrend, rechargeTrend, "day")
|
||
} else if period == "month" {
|
||
// 获取消费趋势
|
||
consumptionTrend, err := s.walletTransactionRepo.GetSystemMonthlyStats(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取消费趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
// 获取充值趋势
|
||
rechargeTrend, err := s.rechargeRecordRepo.GetSystemMonthlyStats(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取充值趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
// 合并趋势数据
|
||
trendData = s.mergeFinanceTrends(consumptionTrend, rechargeTrend, "month")
|
||
}
|
||
} else {
|
||
// 默认获取最近7天的数据
|
||
endDate := time.Now()
|
||
startDate := endDate.AddDate(0, 0, -7)
|
||
consumptionTrend, err := s.walletTransactionRepo.GetSystemDailyStats(ctx, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取消费每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
rechargeTrend, err := s.rechargeRecordRepo.GetSystemDailyStats(ctx, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取充值每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
trendData = s.mergeFinanceTrends(consumptionTrend, rechargeTrend, "day")
|
||
}
|
||
|
||
stats := map[string]interface{}{
|
||
"total_deduct": totalConsumption,
|
||
"deduct_today": todayConsumption,
|
||
"total_recharge": totalRecharge,
|
||
"recharge_today": todayRecharge,
|
||
"daily_trend": trendData,
|
||
}
|
||
return stats, nil
|
||
}
|
||
|
||
// mergeFinanceTrends 合并财务趋势数据
|
||
func (s *StatisticsApplicationServiceImpl) mergeFinanceTrends(consumptionTrend, rechargeTrend []map[string]interface{}, period string) []map[string]interface{} {
|
||
// 创建日期到数据的映射
|
||
consumptionMap := make(map[string]float64)
|
||
rechargeMap := make(map[string]float64)
|
||
|
||
// 处理消费数据
|
||
for _, item := range consumptionTrend {
|
||
var dateKey string
|
||
var amount float64
|
||
|
||
if period == "day" {
|
||
if date, ok := item["date"].(string); ok {
|
||
dateKey = date
|
||
}
|
||
if amt, ok := item["amount"].(float64); ok {
|
||
amount = amt
|
||
}
|
||
} else if period == "month" {
|
||
if month, ok := item["month"].(string); ok {
|
||
dateKey = month
|
||
}
|
||
if amt, ok := item["amount"].(float64); ok {
|
||
amount = amt
|
||
}
|
||
}
|
||
|
||
if dateKey != "" {
|
||
consumptionMap[dateKey] = amount
|
||
}
|
||
}
|
||
|
||
// 处理充值数据
|
||
for _, item := range rechargeTrend {
|
||
var dateKey string
|
||
var amount float64
|
||
|
||
if period == "day" {
|
||
if date, ok := item["date"].(string); ok {
|
||
dateKey = date
|
||
}
|
||
if amt, ok := item["amount"].(float64); ok {
|
||
amount = amt
|
||
}
|
||
} else if period == "month" {
|
||
if month, ok := item["month"].(string); ok {
|
||
dateKey = month
|
||
}
|
||
if amt, ok := item["amount"].(float64); ok {
|
||
amount = amt
|
||
}
|
||
}
|
||
|
||
if dateKey != "" {
|
||
rechargeMap[dateKey] = amount
|
||
}
|
||
}
|
||
|
||
// 合并数据
|
||
var mergedTrend []map[string]interface{}
|
||
allDates := make(map[string]bool)
|
||
|
||
// 收集所有日期
|
||
for date := range consumptionMap {
|
||
allDates[date] = true
|
||
}
|
||
for date := range rechargeMap {
|
||
allDates[date] = true
|
||
}
|
||
|
||
// 按日期排序并合并
|
||
for date := range allDates {
|
||
consumption := consumptionMap[date]
|
||
recharge := rechargeMap[date]
|
||
|
||
item := map[string]interface{}{
|
||
"date": date,
|
||
"deduct": consumption,
|
||
"recharge": recharge,
|
||
}
|
||
mergedTrend = append(mergedTrend, item)
|
||
}
|
||
|
||
// 简单排序(按日期字符串)
|
||
for i := 0; i < len(mergedTrend)-1; i++ {
|
||
for j := i + 1; j < len(mergedTrend); j++ {
|
||
if mergedTrend[i]["date"].(string) > mergedTrend[j]["date"].(string) {
|
||
mergedTrend[i], mergedTrend[j] = mergedTrend[j], mergedTrend[i]
|
||
}
|
||
}
|
||
}
|
||
|
||
return mergedTrend
|
||
}
|
||
|
||
// getUserDailyTrend 获取用户每日趋势
|
||
func (s *StatisticsApplicationServiceImpl) getUserDailyTrend(ctx context.Context, days int) ([]map[string]interface{}, error) {
|
||
// 生成最近N天的日期列表
|
||
var trend []map[string]interface{}
|
||
now := time.Now()
|
||
|
||
for i := days - 1; i >= 0; i-- {
|
||
date := now.AddDate(0, 0, -i).Truncate(24 * time.Hour)
|
||
|
||
// 这里需要实现按日期查询用户注册数的逻辑
|
||
// 暂时使用模拟数据
|
||
count := int64(10 + i*2) // 模拟数据
|
||
|
||
trend = append(trend, map[string]interface{}{
|
||
"date": date.Format("2006-01-02"),
|
||
"count": count,
|
||
})
|
||
}
|
||
|
||
return trend, nil
|
||
}
|
||
|
||
// getCertificationDailyTrend 获取认证每日趋势
|
||
func (s *StatisticsApplicationServiceImpl) getCertificationDailyTrend(ctx context.Context, days int) ([]map[string]interface{}, error) {
|
||
// 生成最近N天的日期列表
|
||
var trend []map[string]interface{}
|
||
now := time.Now()
|
||
|
||
for i := days - 1; i >= 0; i-- {
|
||
date := now.AddDate(0, 0, -i).Truncate(24 * time.Hour)
|
||
|
||
// 这里需要实现按日期查询认证数的逻辑
|
||
// 暂时使用模拟数据
|
||
count := int64(5 + i) // 模拟数据
|
||
|
||
trend = append(trend, map[string]interface{}{
|
||
"date": date.Format("2006-01-02"),
|
||
"count": count,
|
||
})
|
||
}
|
||
|
||
return trend, nil
|
||
}
|
||
|
||
// getWalletTransactionsByDateRange 获取指定日期范围内的钱包交易金额
|
||
func (s *StatisticsApplicationServiceImpl) getWalletTransactionsByDateRange(ctx context.Context, userID string, startDate, endDate time.Time) (float64, error) {
|
||
// 这里需要实现按日期范围查询钱包交易金额的逻辑
|
||
// 暂时返回0,实际实现需要扩展仓储接口或使用原生SQL查询
|
||
return 0.0, nil
|
||
}
|
||
|
||
// getRechargeRecordsByDateRange 获取指定日期范围内的充值金额(排除赠送)
|
||
func (s *StatisticsApplicationServiceImpl) getRechargeRecordsByDateRange(ctx context.Context, userID string, startDate, endDate time.Time) (float64, error) {
|
||
return s.rechargeRecordRepo.GetTotalAmountByUserIdAndDateRange(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
// ================ 独立统计接口实现 ================
|
||
|
||
// GetApiCallsStatistics 获取API调用统计
|
||
func (s *StatisticsApplicationServiceImpl) GetApiCallsStatistics(ctx context.Context, userID string, startDate, endDate time.Time, unit string) (*QueryResponse, error) {
|
||
s.logger.Info("获取API调用统计",
|
||
zap.String("user_id", userID),
|
||
zap.Time("start_date", startDate),
|
||
zap.Time("end_date", endDate),
|
||
zap.String("unit", unit))
|
||
|
||
// 获取总调用次数
|
||
totalCalls, err := s.apiCallRepo.CountByUserId(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用总数失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取指定时间范围内的调用次数
|
||
rangeCalls, err := s.apiCallRepo.CountByUserIdAndDateRange(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用范围统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
var trendData []map[string]interface{}
|
||
if unit == "day" {
|
||
trendData, err = s.apiCallRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
} else if unit == "month" {
|
||
trendData, err = s.apiCallRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取API调用趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"total_calls": totalCalls,
|
||
"range_calls": rangeCalls,
|
||
"trend_data": trendData,
|
||
"unit": unit,
|
||
"start_date": startDate.Format("2006-01-02"),
|
||
"end_date": endDate.Format("2006-01-02"),
|
||
"user_id": userID,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取API调用统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// GetConsumptionStatistics 获取消费统计
|
||
func (s *StatisticsApplicationServiceImpl) GetConsumptionStatistics(ctx context.Context, userID string, startDate, endDate time.Time, unit string) (*QueryResponse, error) {
|
||
s.logger.Info("获取消费统计",
|
||
zap.String("user_id", userID),
|
||
zap.Time("start_date", startDate),
|
||
zap.Time("end_date", endDate),
|
||
zap.String("unit", unit))
|
||
|
||
// 获取总消费金额
|
||
totalAmount, err := s.walletTransactionRepo.GetTotalAmountByUserId(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取消费总金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取指定时间范围内的消费金额
|
||
rangeAmount, err := s.walletTransactionRepo.GetTotalAmountByUserIdAndDateRange(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取消费范围统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
var trendData []map[string]interface{}
|
||
if unit == "day" {
|
||
trendData, err = s.walletTransactionRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
} else if unit == "month" {
|
||
trendData, err = s.walletTransactionRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取消费趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"total_amount": totalAmount,
|
||
"range_amount": rangeAmount,
|
||
"trend_data": trendData,
|
||
"unit": unit,
|
||
"start_date": startDate.Format("2006-01-02"),
|
||
"end_date": endDate.Format("2006-01-02"),
|
||
"user_id": userID,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取消费统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// GetRechargeStatistics 获取充值统计
|
||
func (s *StatisticsApplicationServiceImpl) GetRechargeStatistics(ctx context.Context, userID string, startDate, endDate time.Time, unit string) (*QueryResponse, error) {
|
||
s.logger.Info("获取充值统计",
|
||
zap.String("user_id", userID),
|
||
zap.Time("start_date", startDate),
|
||
zap.Time("end_date", endDate),
|
||
zap.String("unit", unit))
|
||
|
||
// 获取总充值金额
|
||
totalAmount, err := s.rechargeRecordRepo.GetTotalAmountByUserId(ctx, userID)
|
||
if err != nil {
|
||
s.logger.Error("获取充值总金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取指定时间范围内的充值金额
|
||
rangeAmount, err := s.rechargeRecordRepo.GetTotalAmountByUserIdAndDateRange(ctx, userID, startDate, endDate)
|
||
if err != nil {
|
||
s.logger.Error("获取充值范围统计失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
var trendData []map[string]interface{}
|
||
if unit == "day" {
|
||
trendData, err = s.rechargeRecordRepo.GetDailyStatsByUserId(ctx, userID, startDate, endDate)
|
||
} else if unit == "month" {
|
||
trendData, err = s.rechargeRecordRepo.GetMonthlyStatsByUserId(ctx, userID, startDate, endDate)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取充值趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"total_amount": totalAmount,
|
||
"range_amount": rangeAmount,
|
||
"trend_data": trendData,
|
||
"unit": unit,
|
||
"start_date": startDate.Format("2006-01-02"),
|
||
"end_date": endDate.Format("2006-01-02"),
|
||
"user_id": userID,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取充值统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// GetLatestProducts 获取最新产品推荐
|
||
func (s *StatisticsApplicationServiceImpl) GetLatestProducts(ctx context.Context, limit int) (*QueryResponse, error) {
|
||
s.logger.Info("获取最新产品推荐", zap.Int("limit", limit))
|
||
|
||
// 获取最新的产品
|
||
query := &productQueries.ListProductsQuery{
|
||
Page: 1,
|
||
PageSize: limit,
|
||
IsVisible: &[]bool{true}[0],
|
||
IsEnabled: &[]bool{true}[0],
|
||
SortBy: "created_at",
|
||
SortOrder: "desc",
|
||
}
|
||
|
||
productsList, _, err := s.productRepo.ListProducts(ctx, query)
|
||
if err != nil {
|
||
s.logger.Error("获取最新产品失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
var products []map[string]interface{}
|
||
for _, product := range productsList {
|
||
products = append(products, map[string]interface{}{
|
||
"id": product.ID,
|
||
"name": product.Name,
|
||
"description": product.Description,
|
||
"code": product.Code,
|
||
"price": product.Price,
|
||
"category_id": product.CategoryID,
|
||
"created_at": product.CreatedAt,
|
||
"is_new": true, // 暂时都标记为新产品
|
||
})
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"products": products,
|
||
"count": len(products),
|
||
"limit": limit,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取最新产品推荐成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// ================ 管理员独立域统计接口 ================
|
||
|
||
// AdminGetUserDomainStatistics 管理员获取用户域统计
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetUserDomainStatistics(ctx context.Context, period, startDate, endDate string) (*QueryResponse, error) {
|
||
s.logger.Info("管理员获取用户域统计", zap.String("period", period), zap.String("startDate", startDate), zap.String("endDate", endDate))
|
||
|
||
// 解析日期
|
||
var startTime, endTime time.Time
|
||
var err error
|
||
if startDate != "" {
|
||
startTime, err = time.Parse("2006-01-02", startDate)
|
||
if err != nil {
|
||
s.logger.Error("解析开始日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
if endDate != "" {
|
||
endTime, err = time.Parse("2006-01-02", endDate)
|
||
if err != nil {
|
||
s.logger.Error("解析结束日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 获取用户统计数据
|
||
userStats, err := s.getUserStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取用户统计数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取认证统计数据
|
||
certificationStats, err := s.getCertificationStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取认证统计数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"user_stats": userStats,
|
||
"certification_stats": certificationStats,
|
||
"period": period,
|
||
"start_date": startDate,
|
||
"end_date": endDate,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取用户域统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetApiDomainStatistics 管理员获取API域统计
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetApiDomainStatistics(ctx context.Context, period, startDate, endDate string) (*QueryResponse, error) {
|
||
s.logger.Info("管理员获取API域统计", zap.String("period", period), zap.String("startDate", startDate), zap.String("endDate", endDate))
|
||
|
||
// 解析日期
|
||
var startTime, endTime time.Time
|
||
var err error
|
||
if startDate != "" {
|
||
startTime, err = time.Parse("2006-01-02", startDate)
|
||
if err != nil {
|
||
s.logger.Error("解析开始日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
if endDate != "" {
|
||
endTime, err = time.Parse("2006-01-02", endDate)
|
||
if err != nil {
|
||
s.logger.Error("解析结束日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 获取API调用统计数据
|
||
apiCallStats, err := s.getSystemApiCallStats(ctx, period, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取API调用统计数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"api_call_stats": apiCallStats,
|
||
"period": period,
|
||
"start_date": startDate,
|
||
"end_date": endDate,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取API域统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetConsumptionDomainStatistics 管理员获取消费域统计
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetConsumptionDomainStatistics(ctx context.Context, period, startDate, endDate string) (*QueryResponse, error) {
|
||
s.logger.Info("管理员获取消费域统计", zap.String("period", period), zap.String("startDate", startDate), zap.String("endDate", endDate))
|
||
|
||
// 解析日期
|
||
var startTime, endTime time.Time
|
||
var err error
|
||
if startDate != "" {
|
||
startTime, err = time.Parse("2006-01-02", startDate)
|
||
if err != nil {
|
||
s.logger.Error("解析开始日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
if endDate != "" {
|
||
endTime, err = time.Parse("2006-01-02", endDate)
|
||
if err != nil {
|
||
s.logger.Error("解析结束日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 获取消费统计数据
|
||
totalConsumption, err := s.walletTransactionRepo.GetSystemTotalAmount(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取系统总消费金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日消费金额
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayConsumption, err := s.walletTransactionRepo.GetSystemAmountByDateRange(ctx, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日消费金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取指定时间范围内的消费金额
|
||
rangeConsumption := float64(0)
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
rangeConsumption, err = s.walletTransactionRepo.GetSystemAmountByDateRange(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取指定时间范围消费金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
var consumptionTrend []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
consumptionTrend, err = s.walletTransactionRepo.GetSystemDailyStats(ctx, startTime, endTime)
|
||
} else if period == "month" {
|
||
consumptionTrend, err = s.walletTransactionRepo.GetSystemMonthlyStats(ctx, startTime, endTime)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取消费趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 如果没有指定时间范围,获取最近7天的数据
|
||
defaultEndDate := time.Now()
|
||
defaultStartDate := defaultEndDate.AddDate(0, 0, -7)
|
||
consumptionTrend, err = s.walletTransactionRepo.GetSystemDailyStats(ctx, defaultStartDate, defaultEndDate)
|
||
if err != nil {
|
||
s.logger.Error("获取消费每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"total_consumption": totalConsumption,
|
||
"today_consumption": todayConsumption,
|
||
"range_consumption": rangeConsumption,
|
||
"consumption_trend": consumptionTrend,
|
||
"period": period,
|
||
"start_date": startDate,
|
||
"end_date": endDate,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取消费域统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetRechargeDomainStatistics 管理员获取充值域统计
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetRechargeDomainStatistics(ctx context.Context, period, startDate, endDate string) (*QueryResponse, error) {
|
||
s.logger.Info("管理员获取充值域统计", zap.String("period", period), zap.String("startDate", startDate), zap.String("endDate", endDate))
|
||
|
||
// 解析日期
|
||
var startTime, endTime time.Time
|
||
var err error
|
||
if startDate != "" {
|
||
startTime, err = time.Parse("2006-01-02", startDate)
|
||
if err != nil {
|
||
s.logger.Error("解析开始日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
if endDate != "" {
|
||
endTime, err = time.Parse("2006-01-02", endDate)
|
||
if err != nil {
|
||
s.logger.Error("解析结束日期失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 获取充值统计数据
|
||
totalRecharge, err := s.rechargeRecordRepo.GetSystemTotalAmount(ctx)
|
||
if err != nil {
|
||
s.logger.Error("获取系统总充值金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取今日充值金额
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
todayRecharge, err := s.rechargeRecordRepo.GetSystemAmountByDateRange(ctx, today, tomorrow)
|
||
if err != nil {
|
||
s.logger.Error("获取今日充值金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 获取指定时间范围内的充值金额
|
||
rangeRecharge := float64(0)
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
rangeRecharge, err = s.rechargeRecordRepo.GetSystemAmountByDateRange(ctx, startTime, endTime)
|
||
if err != nil {
|
||
s.logger.Error("获取指定时间范围充值金额失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
var rechargeTrend []map[string]interface{}
|
||
if !startTime.IsZero() && !endTime.IsZero() {
|
||
if period == "day" {
|
||
rechargeTrend, err = s.rechargeRecordRepo.GetSystemDailyStats(ctx, startTime, endTime)
|
||
} else if period == "month" {
|
||
rechargeTrend, err = s.rechargeRecordRepo.GetSystemMonthlyStats(ctx, startTime, endTime)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取充值趋势数据失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 如果没有指定时间范围,获取最近7天的数据
|
||
defaultEndDate := time.Now()
|
||
defaultStartDate := defaultEndDate.AddDate(0, 0, -7)
|
||
rechargeTrend, err = s.rechargeRecordRepo.GetSystemDailyStats(ctx, defaultStartDate, defaultEndDate)
|
||
if err != nil {
|
||
s.logger.Error("获取充值每日趋势失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"total_recharge": totalRecharge,
|
||
"today_recharge": todayRecharge,
|
||
"range_recharge": rangeRecharge,
|
||
"recharge_trend": rechargeTrend,
|
||
"period": period,
|
||
"start_date": startDate,
|
||
"end_date": endDate,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取充值域统计成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetUserCallRanking 获取用户调用排行榜
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetUserCallRanking(ctx context.Context, rankingType, period string, limit int) (*QueryResponse, error) {
|
||
s.logger.Info("获取用户调用排行榜", zap.String("type", rankingType), zap.String("period", period), zap.Int("limit", limit))
|
||
|
||
var rankings []map[string]interface{}
|
||
var err error
|
||
|
||
switch rankingType {
|
||
case "calls":
|
||
// 按调用次数排行
|
||
switch period {
|
||
case "today":
|
||
rankings, err = s.getUserCallRankingByCalls(ctx, "today", limit)
|
||
case "month":
|
||
rankings, err = s.getUserCallRankingByCalls(ctx, "month", limit)
|
||
case "total":
|
||
rankings, err = s.getUserCallRankingByCalls(ctx, "total", limit)
|
||
default:
|
||
return nil, fmt.Errorf("不支持的时间周期: %s", period)
|
||
}
|
||
case "consumption":
|
||
// 按消费金额排行
|
||
switch period {
|
||
case "today":
|
||
rankings, err = s.getUserCallRankingByConsumption(ctx, "today", limit)
|
||
case "month":
|
||
rankings, err = s.getUserCallRankingByConsumption(ctx, "month", limit)
|
||
case "total":
|
||
rankings, err = s.getUserCallRankingByConsumption(ctx, "total", limit)
|
||
default:
|
||
return nil, fmt.Errorf("不支持的时间周期: %s", period)
|
||
}
|
||
default:
|
||
return nil, fmt.Errorf("不支持的排行类型: %s", rankingType)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取用户调用排行榜失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"ranking_type": rankingType,
|
||
"period": period,
|
||
"limit": limit,
|
||
"rankings": rankings,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取用户调用排行榜成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetRechargeRanking 获取充值排行榜
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetRechargeRanking(ctx context.Context, period string, limit int) (*QueryResponse, error) {
|
||
s.logger.Info("获取充值排行榜", zap.String("period", period), zap.Int("limit", limit))
|
||
|
||
var rankings []map[string]interface{}
|
||
var err error
|
||
|
||
switch period {
|
||
case "today":
|
||
rankings, err = s.getRechargeRanking(ctx, "today", limit)
|
||
case "month":
|
||
rankings, err = s.getRechargeRanking(ctx, "month", limit)
|
||
case "total":
|
||
rankings, err = s.getRechargeRanking(ctx, "total", limit)
|
||
default:
|
||
return nil, fmt.Errorf("不支持的时间周期: %s", period)
|
||
}
|
||
|
||
if err != nil {
|
||
s.logger.Error("获取充值排行榜失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"period": period,
|
||
"limit": limit,
|
||
"rankings": rankings,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取充值排行榜成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// getUserCallRankingByCalls 按调用次数获取用户排行
|
||
func (s *StatisticsApplicationServiceImpl) getUserCallRankingByCalls(ctx context.Context, period string, limit int) ([]map[string]interface{}, error) {
|
||
// 调用用户仓储获取真实数据
|
||
rankings, err := s.userRepo.GetUserCallRankingByCalls(ctx, period, limit)
|
||
if err != nil {
|
||
s.logger.Error("获取用户调用次数排行失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 添加排名信息
|
||
for i, ranking := range rankings {
|
||
ranking["rank"] = i + 1
|
||
}
|
||
|
||
return rankings, nil
|
||
}
|
||
|
||
// getUserCallRankingByConsumption 按消费金额获取用户排行
|
||
func (s *StatisticsApplicationServiceImpl) getUserCallRankingByConsumption(ctx context.Context, period string, limit int) ([]map[string]interface{}, error) {
|
||
// 调用用户仓储获取真实数据
|
||
rankings, err := s.userRepo.GetUserCallRankingByConsumption(ctx, period, limit)
|
||
if err != nil {
|
||
s.logger.Error("获取用户消费金额排行失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 添加排名信息
|
||
for i, ranking := range rankings {
|
||
ranking["rank"] = i + 1
|
||
}
|
||
|
||
return rankings, nil
|
||
}
|
||
|
||
// getRechargeRanking 获取充值排行
|
||
func (s *StatisticsApplicationServiceImpl) getRechargeRanking(ctx context.Context, period string, limit int) ([]map[string]interface{}, error) {
|
||
// 调用用户仓储获取真实数据
|
||
rankings, err := s.userRepo.GetRechargeRanking(ctx, period, limit)
|
||
if err != nil {
|
||
s.logger.Error("获取充值排行失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 添加排名信息
|
||
for i, ranking := range rankings {
|
||
ranking["rank"] = i + 1
|
||
}
|
||
|
||
return rankings, nil
|
||
}
|
||
|
||
// AdminGetApiPopularityRanking 获取API受欢迎程度排行榜
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetApiPopularityRanking(ctx context.Context, period string, limit int) (*QueryResponse, error) {
|
||
s.logger.Info("获取API受欢迎程度排行榜", zap.String("period", period), zap.Int("limit", limit))
|
||
|
||
// 调用API调用仓储获取真实数据
|
||
rankings, err := s.apiCallRepo.GetApiPopularityRanking(ctx, period, limit)
|
||
if err != nil {
|
||
s.logger.Error("获取API受欢迎程度排行榜失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
// 添加排名信息
|
||
for i, ranking := range rankings {
|
||
ranking["rank"] = i + 1
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"period": period,
|
||
"limit": limit,
|
||
"rankings": rankings,
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取API受欢迎程度排行榜成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|
||
|
||
// AdminGetTodayCertifiedEnterprises 获取今日认证企业列表
|
||
func (s *StatisticsApplicationServiceImpl) AdminGetTodayCertifiedEnterprises(ctx context.Context, limit int) (*QueryResponse, error) {
|
||
// 获取今日开始和结束时间
|
||
now := time.Now()
|
||
todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||
todayEnd := todayStart.Add(24 * time.Hour)
|
||
|
||
// 查询所有已完成的认证,然后过滤今日完成的
|
||
query := &certificationQueries.ListCertificationsQuery{
|
||
Page: 1,
|
||
PageSize: 1000, // 设置较大的页面大小以获取所有数据
|
||
SortBy: "updated_at",
|
||
SortOrder: "desc",
|
||
Status: certificationEnums.StatusCompleted,
|
||
}
|
||
|
||
certifications, _, err := s.certificationRepo.List(ctx, query)
|
||
if err != nil {
|
||
s.logger.Error("获取今日认证企业失败", zap.Error(err))
|
||
return nil, fmt.Errorf("获取今日认证企业失败: %w", err)
|
||
}
|
||
|
||
// 过滤出今日完成的认证(基于completed_at字段)
|
||
var completedCertifications []*certificationEntities.Certification
|
||
for _, cert := range certifications {
|
||
if cert.CompletedAt != nil &&
|
||
cert.CompletedAt.After(todayStart) &&
|
||
cert.CompletedAt.Before(todayEnd) {
|
||
completedCertifications = append(completedCertifications, cert)
|
||
}
|
||
}
|
||
|
||
// 按完成时间排序(最新的在前)
|
||
for i := 0; i < len(completedCertifications)-1; i++ {
|
||
for j := i + 1; j < len(completedCertifications); j++ {
|
||
if completedCertifications[i].CompletedAt.Before(*completedCertifications[j].CompletedAt) {
|
||
completedCertifications[i], completedCertifications[j] = completedCertifications[j], completedCertifications[i]
|
||
}
|
||
}
|
||
}
|
||
|
||
// 限制返回数量
|
||
if limit > 0 && len(completedCertifications) > limit {
|
||
completedCertifications = completedCertifications[:limit]
|
||
}
|
||
|
||
// 直接从企业信息表获取数据
|
||
var enterprises []map[string]interface{}
|
||
for _, cert := range completedCertifications {
|
||
// 获取企业信息
|
||
enterpriseInfo, err := s.enterpriseInfoRepo.GetByUserID(ctx, cert.UserID)
|
||
if err != nil {
|
||
s.logger.Warn("获取企业信息失败", zap.String("user_id", cert.UserID), zap.Error(err))
|
||
continue
|
||
}
|
||
|
||
// 获取用户基本信息(仅需要用户名)
|
||
user, err := s.userRepo.GetByID(ctx, cert.UserID)
|
||
if err != nil {
|
||
s.logger.Warn("获取用户信息失败", zap.String("user_id", cert.UserID), zap.Error(err))
|
||
continue
|
||
}
|
||
|
||
enterprise := map[string]interface{}{
|
||
"id": cert.ID,
|
||
"user_id": cert.UserID,
|
||
"username": user.Username,
|
||
"enterprise_name": enterpriseInfo.CompanyName,
|
||
"legal_person_name": enterpriseInfo.LegalPersonName,
|
||
"legal_person_phone": enterpriseInfo.LegalPersonPhone,
|
||
"unified_social_code": enterpriseInfo.UnifiedSocialCode,
|
||
"enterprise_address": enterpriseInfo.EnterpriseAddress,
|
||
"certified_at": cert.CompletedAt.Format(time.RFC3339),
|
||
}
|
||
enterprises = append(enterprises, enterprise)
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"enterprises": enterprises,
|
||
"total": len(enterprises),
|
||
"date": todayStart.Format("2006-01-02"),
|
||
}
|
||
|
||
return &QueryResponse{
|
||
Success: true,
|
||
Message: "获取今日认证企业列表成功",
|
||
Data: result,
|
||
}, nil
|
||
}
|