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 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, 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, 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) { // 这里需要实现按日期范围查询充值金额的逻辑 // 暂时返回0,实际实现需要扩展仓储接口或使用原生SQL查询 return 0.0, nil } // ================ 独立统计接口实现 ================ // 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 } todayConsumption := float64(0) if !startTime.IsZero() && !endTime.IsZero() { todayConsumption, 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 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 } result := map[string]interface{}{ "total_consumption": totalConsumption, "range_consumption": todayConsumption, "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 } todayRecharge := float64(0) if !startTime.IsZero() && !endTime.IsZero() { todayRecharge, 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 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 } result := map[string]interface{}{ "total_recharge": totalRecharge, "range_recharge": todayRecharge, "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 { user, err := s.userRepo.GetByID(ctx, cert.UserID) if err != nil { s.logger.Warn("获取用户信息失败", zap.String("user_id", cert.UserID), zap.Error(err)) continue } enterpriseName := "" if user.EnterpriseInfo != nil { enterpriseName = user.EnterpriseInfo.CompanyName } enterprise := map[string]interface{}{ "id": cert.ID, "user_id": cert.UserID, "username": user.Username, "enterprise_name": enterpriseName, "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 }