Files
tyapi-server/internal/application/statistics/statistics_application_service_impl.go

2692 lines
82 KiB
Go
Raw Normal View History

2025-09-12 01:15:09 +08:00
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
}