Files
tyapi-server/internal/application/statistics/statistics_application_service_impl.go
2025-09-14 16:34:55 +08:00

2746 lines
84 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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