583 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			583 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package services
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	"go.uber.org/zap"
 | |
| 
 | |
| 	"tyapi-server/internal/domains/statistics/entities"
 | |
| 	"tyapi-server/internal/domains/statistics/repositories"
 | |
| )
 | |
| 
 | |
| // StatisticsReportService 报告生成服务接口
 | |
| // 负责统计报告的生成和管理
 | |
| type StatisticsReportService interface {
 | |
| 	// 报告生成
 | |
| 	GenerateDashboardReport(ctx context.Context, userRole string, period string) (*entities.StatisticsReport, error)
 | |
| 	GenerateSummaryReport(ctx context.Context, period string, startDate, endDate time.Time) (*entities.StatisticsReport, error)
 | |
| 	GenerateDetailedReport(ctx context.Context, reportType string, startDate, endDate time.Time, filters map[string]interface{}) (*entities.StatisticsReport, error)
 | |
| 	
 | |
| 	// 报告管理
 | |
| 	GetReport(ctx context.Context, reportID string) (*entities.StatisticsReport, error)
 | |
| 	GetReportsByUser(ctx context.Context, userID string, limit, offset int) ([]*entities.StatisticsReport, error)
 | |
| 	DeleteReport(ctx context.Context, reportID string) error
 | |
| 	
 | |
| 	// 报告状态管理
 | |
| 	StartReportGeneration(ctx context.Context, reportID, generatedBy string) error
 | |
| 	CompleteReportGeneration(ctx context.Context, reportID string, content string) error
 | |
| 	FailReportGeneration(ctx context.Context, reportID string, reason string) error
 | |
| 	
 | |
| 	// 报告清理
 | |
| 	CleanupExpiredReports(ctx context.Context) error
 | |
| }
 | |
| 
 | |
| // StatisticsReportServiceImpl 报告生成服务实现
 | |
| type StatisticsReportServiceImpl struct {
 | |
| 	reportRepo repositories.StatisticsReportRepository
 | |
| 	metricRepo repositories.StatisticsRepository
 | |
| 	calcService StatisticsCalculationService
 | |
| 	logger      *zap.Logger
 | |
| }
 | |
| 
 | |
| // NewStatisticsReportService 创建报告生成服务
 | |
| func NewStatisticsReportService(
 | |
| 	reportRepo repositories.StatisticsReportRepository,
 | |
| 	metricRepo repositories.StatisticsRepository,
 | |
| 	calcService StatisticsCalculationService,
 | |
| 	logger *zap.Logger,
 | |
| ) StatisticsReportService {
 | |
| 	return &StatisticsReportServiceImpl{
 | |
| 		reportRepo: reportRepo,
 | |
| 		metricRepo: metricRepo,
 | |
| 		calcService: calcService,
 | |
| 		logger:      logger,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // GenerateDashboardReport 生成仪表板报告
 | |
| func (s *StatisticsReportServiceImpl) GenerateDashboardReport(ctx context.Context, userRole string, period string) (*entities.StatisticsReport, error) {
 | |
| 	if userRole == "" {
 | |
| 		return nil, fmt.Errorf("用户角色不能为空")
 | |
| 	}
 | |
| 	if period == "" {
 | |
| 		return nil, fmt.Errorf("统计周期不能为空")
 | |
| 	}
 | |
| 
 | |
| 	// 创建报告实体
 | |
| 	title := fmt.Sprintf("%s仪表板报告 - %s", s.getRoleDisplayName(userRole), s.getPeriodDisplayName(period))
 | |
| 	report, err := entities.NewStatisticsReport("dashboard", title, period, userRole)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("创建仪表板报告失败", 
 | |
| 			zap.String("user_role", userRole),
 | |
| 			zap.String("period", period),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("创建仪表板报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 保存报告
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存仪表板报告失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("保存仪表板报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("仪表板报告创建成功",
 | |
| 		zap.String("report_id", report.ID),
 | |
| 		zap.String("user_role", userRole),
 | |
| 		zap.String("period", period))
 | |
| 
 | |
| 	return report, nil
 | |
| }
 | |
| 
 | |
| // GenerateSummaryReport 生成汇总报告
 | |
| func (s *StatisticsReportServiceImpl) GenerateSummaryReport(ctx context.Context, period string, startDate, endDate time.Time) (*entities.StatisticsReport, error) {
 | |
| 	if period == "" {
 | |
| 		return nil, fmt.Errorf("统计周期不能为空")
 | |
| 	}
 | |
| 
 | |
| 	// 创建报告实体
 | |
| 	title := fmt.Sprintf("汇总报告 - %s (%s 至 %s)", 
 | |
| 		s.getPeriodDisplayName(period), 
 | |
| 		startDate.Format("2006-01-02"), 
 | |
| 		endDate.Format("2006-01-02"))
 | |
| 	report, err := entities.NewStatisticsReport("summary", title, period, "admin")
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("创建汇总报告失败", 
 | |
| 			zap.String("period", period),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("创建汇总报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 生成报告内容
 | |
| 	content, err := s.generateSummaryContent(ctx, startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("生成汇总报告内容失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("生成汇总报告内容失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 完成报告生成
 | |
| 	err = report.CompleteGeneration(content)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("完成汇总报告生成失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("完成汇总报告生成失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 保存报告
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存汇总报告失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("保存汇总报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("汇总报告生成成功",
 | |
| 		zap.String("report_id", report.ID),
 | |
| 		zap.String("period", period))
 | |
| 
 | |
| 	return report, nil
 | |
| }
 | |
| 
 | |
| // GenerateDetailedReport 生成详细报告
 | |
| func (s *StatisticsReportServiceImpl) GenerateDetailedReport(ctx context.Context, reportType string, startDate, endDate time.Time, filters map[string]interface{}) (*entities.StatisticsReport, error) {
 | |
| 	if reportType == "" {
 | |
| 		return nil, fmt.Errorf("报告类型不能为空")
 | |
| 	}
 | |
| 
 | |
| 	// 创建报告实体
 | |
| 	title := fmt.Sprintf("详细报告 - %s (%s 至 %s)", 
 | |
| 		reportType, 
 | |
| 		startDate.Format("2006-01-02"), 
 | |
| 		endDate.Format("2006-01-02"))
 | |
| 	report, err := entities.NewStatisticsReport("detailed", title, "custom", "admin")
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("创建详细报告失败", 
 | |
| 			zap.String("report_type", reportType),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("创建详细报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 生成报告内容
 | |
| 	content, err := s.generateDetailedContent(ctx, reportType, startDate, endDate, filters)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("生成详细报告内容失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("生成详细报告内容失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 完成报告生成
 | |
| 	err = report.CompleteGeneration(content)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("完成详细报告生成失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("完成详细报告生成失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 保存报告
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存详细报告失败", 
 | |
| 			zap.String("report_id", report.ID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("保存详细报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("详细报告生成成功",
 | |
| 		zap.String("report_id", report.ID),
 | |
| 		zap.String("report_type", reportType))
 | |
| 
 | |
| 	return report, nil
 | |
| }
 | |
| 
 | |
| // GetReport 获取报告
 | |
| func (s *StatisticsReportServiceImpl) GetReport(ctx context.Context, reportID string) (*entities.StatisticsReport, error) {
 | |
| 	if reportID == "" {
 | |
| 		return nil, fmt.Errorf("报告ID不能为空")
 | |
| 	}
 | |
| 
 | |
| 	report, err := s.reportRepo.FindByID(ctx, reportID)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("查询报告失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("查询报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return report, nil
 | |
| }
 | |
| 
 | |
| // GetReportsByUser 获取用户的报告列表
 | |
| func (s *StatisticsReportServiceImpl) GetReportsByUser(ctx context.Context, userID string, limit, offset int) ([]*entities.StatisticsReport, error) {
 | |
| 	if userID == "" {
 | |
| 		return nil, fmt.Errorf("用户ID不能为空")
 | |
| 	}
 | |
| 
 | |
| 	reports, err := s.reportRepo.FindByUser(ctx, userID, limit, offset)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("查询用户报告失败", 
 | |
| 			zap.String("user_id", userID),
 | |
| 			zap.Error(err))
 | |
| 		return nil, fmt.Errorf("查询用户报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return reports, nil
 | |
| }
 | |
| 
 | |
| // DeleteReport 删除报告
 | |
| func (s *StatisticsReportServiceImpl) DeleteReport(ctx context.Context, reportID string) error {
 | |
| 	if reportID == "" {
 | |
| 		return fmt.Errorf("报告ID不能为空")
 | |
| 	}
 | |
| 
 | |
| 	err := s.reportRepo.Delete(ctx, reportID)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("删除报告失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("删除报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("报告删除成功", zap.String("report_id", reportID))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // StartReportGeneration 开始报告生成
 | |
| func (s *StatisticsReportServiceImpl) StartReportGeneration(ctx context.Context, reportID, generatedBy string) error {
 | |
| 	if reportID == "" {
 | |
| 		return fmt.Errorf("报告ID不能为空")
 | |
| 	}
 | |
| 	if generatedBy == "" {
 | |
| 		return fmt.Errorf("生成者ID不能为空")
 | |
| 	}
 | |
| 
 | |
| 	report, err := s.reportRepo.FindByID(ctx, reportID)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("查询报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = report.StartGeneration(generatedBy)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("开始报告生成失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("开始报告生成失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存报告状态失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("保存报告状态失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("报告生成开始", 
 | |
| 		zap.String("report_id", reportID),
 | |
| 		zap.String("generated_by", generatedBy))
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // CompleteReportGeneration 完成报告生成
 | |
| func (s *StatisticsReportServiceImpl) CompleteReportGeneration(ctx context.Context, reportID string, content string) error {
 | |
| 	if reportID == "" {
 | |
| 		return fmt.Errorf("报告ID不能为空")
 | |
| 	}
 | |
| 	if content == "" {
 | |
| 		return fmt.Errorf("报告内容不能为空")
 | |
| 	}
 | |
| 
 | |
| 	report, err := s.reportRepo.FindByID(ctx, reportID)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("查询报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = report.CompleteGeneration(content)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("完成报告生成失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("完成报告生成失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存报告内容失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("保存报告内容失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("报告生成完成", zap.String("report_id", reportID))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // FailReportGeneration 报告生成失败
 | |
| func (s *StatisticsReportServiceImpl) FailReportGeneration(ctx context.Context, reportID string, reason string) error {
 | |
| 	if reportID == "" {
 | |
| 		return fmt.Errorf("报告ID不能为空")
 | |
| 	}
 | |
| 
 | |
| 	report, err := s.reportRepo.FindByID(ctx, reportID)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("查询报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = report.FailGeneration(reason)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("标记报告生成失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("标记报告生成失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	err = s.reportRepo.Save(ctx, report)
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("保存报告状态失败", 
 | |
| 			zap.String("report_id", reportID),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("保存报告状态失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("报告生成失败", 
 | |
| 		zap.String("report_id", reportID),
 | |
| 		zap.String("reason", reason))
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // CleanupExpiredReports 清理过期报告
 | |
| func (s *StatisticsReportServiceImpl) CleanupExpiredReports(ctx context.Context) error {
 | |
| 	s.logger.Info("开始清理过期报告")
 | |
| 
 | |
| 	// 获取所有已完成的报告
 | |
| 	reports, err := s.reportRepo.FindByStatus(ctx, "completed")
 | |
| 	if err != nil {
 | |
| 		s.logger.Error("查询已完成报告失败", zap.Error(err))
 | |
| 		return fmt.Errorf("查询已完成报告失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	var deletedCount int
 | |
| 	for _, report := range reports {
 | |
| 		if report.IsExpired() {
 | |
| 			err = report.MarkAsExpired()
 | |
| 			if err != nil {
 | |
| 				s.logger.Error("标记报告过期失败", 
 | |
| 					zap.String("report_id", report.ID),
 | |
| 					zap.Error(err))
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			err = s.reportRepo.Save(ctx, report)
 | |
| 			if err != nil {
 | |
| 				s.logger.Error("保存过期报告状态失败", 
 | |
| 					zap.String("report_id", report.ID),
 | |
| 					zap.Error(err))
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			deletedCount++
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	s.logger.Info("过期报告清理完成", zap.Int("deleted_count", deletedCount))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // generateSummaryContent 生成汇总报告内容
 | |
| func (s *StatisticsReportServiceImpl) generateSummaryContent(ctx context.Context, startDate, endDate time.Time) (string, error) {
 | |
| 	content := make(map[string]interface{})
 | |
| 
 | |
| 	// API调用统计
 | |
| 	apiCallsTotal, err := s.calcService.CalculateTotal(ctx, "api_calls", "total_count", startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Warn("计算API调用总数失败", zap.Error(err))
 | |
| 	}
 | |
| 	apiCallsSuccess, err := s.calcService.CalculateTotal(ctx, "api_calls", "success_count", startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Warn("计算API调用成功数失败", zap.Error(err))
 | |
| 	}
 | |
| 
 | |
| 	// 用户统计
 | |
| 	usersTotal, err := s.calcService.CalculateTotal(ctx, "users", "total_count", startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Warn("计算用户总数失败", zap.Error(err))
 | |
| 	}
 | |
| 	usersCertified, err := s.calcService.CalculateTotal(ctx, "users", "certified_count", startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Warn("计算认证用户数失败", zap.Error(err))
 | |
| 	}
 | |
| 
 | |
| 	// 财务统计
 | |
| 	financeTotal, err := s.calcService.CalculateTotal(ctx, "finance", "total_amount", startDate, endDate)
 | |
| 	if err != nil {
 | |
| 		s.logger.Warn("计算财务总额失败", zap.Error(err))
 | |
| 	}
 | |
| 
 | |
| 	content["api_calls"] = map[string]interface{}{
 | |
| 		"total":   apiCallsTotal,
 | |
| 		"success": apiCallsSuccess,
 | |
| 		"rate":    s.calculateRate(apiCallsSuccess, apiCallsTotal),
 | |
| 	}
 | |
| 
 | |
| 	content["users"] = map[string]interface{}{
 | |
| 		"total":     usersTotal,
 | |
| 		"certified": usersCertified,
 | |
| 		"rate":      s.calculateRate(usersCertified, usersTotal),
 | |
| 	}
 | |
| 
 | |
| 	content["finance"] = map[string]interface{}{
 | |
| 		"total_amount": financeTotal,
 | |
| 	}
 | |
| 
 | |
| 	content["period"] = map[string]interface{}{
 | |
| 		"start_date": startDate.Format("2006-01-02"),
 | |
| 		"end_date":   endDate.Format("2006-01-02"),
 | |
| 	}
 | |
| 
 | |
| 	content["generated_at"] = time.Now().Format("2006-01-02 15:04:05")
 | |
| 
 | |
| 	// 转换为JSON字符串
 | |
| 	jsonContent, err := json.Marshal(content)
 | |
| 	if err != nil {
 | |
| 		return "", fmt.Errorf("序列化报告内容失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return string(jsonContent), nil
 | |
| }
 | |
| 
 | |
| // generateDetailedContent 生成详细报告内容
 | |
| func (s *StatisticsReportServiceImpl) generateDetailedContent(ctx context.Context, reportType string, startDate, endDate time.Time, filters map[string]interface{}) (string, error) {
 | |
| 	content := make(map[string]interface{})
 | |
| 
 | |
| 	// 根据报告类型生成不同的内容
 | |
| 	switch reportType {
 | |
| 	case "api_calls":
 | |
| 		content = s.generateApiCallsDetailedContent(ctx, startDate, endDate, filters)
 | |
| 	case "users":
 | |
| 		content = s.generateUsersDetailedContent(ctx, startDate, endDate, filters)
 | |
| 	case "finance":
 | |
| 		content = s.generateFinanceDetailedContent(ctx, startDate, endDate, filters)
 | |
| 	default:
 | |
| 		return "", fmt.Errorf("不支持的报告类型: %s", reportType)
 | |
| 	}
 | |
| 
 | |
| 	content["report_type"] = reportType
 | |
| 	content["period"] = map[string]interface{}{
 | |
| 		"start_date": startDate.Format("2006-01-02"),
 | |
| 		"end_date":   endDate.Format("2006-01-02"),
 | |
| 	}
 | |
| 	content["generated_at"] = time.Now().Format("2006-01-02 15:04:05")
 | |
| 
 | |
| 	// 转换为JSON字符串
 | |
| 	jsonContent, err := json.Marshal(content)
 | |
| 	if err != nil {
 | |
| 		return "", fmt.Errorf("序列化报告内容失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return string(jsonContent), nil
 | |
| }
 | |
| 
 | |
| // generateApiCallsDetailedContent 生成API调用详细内容
 | |
| func (s *StatisticsReportServiceImpl) generateApiCallsDetailedContent(ctx context.Context, startDate, endDate time.Time, filters map[string]interface{}) map[string]interface{} {
 | |
| 	content := make(map[string]interface{})
 | |
| 
 | |
| 	// 获取API调用统计数据
 | |
| 	totalCalls, _ := s.calcService.CalculateTotal(ctx, "api_calls", "total_count", startDate, endDate)
 | |
| 	successCalls, _ := s.calcService.CalculateTotal(ctx, "api_calls", "success_count", startDate, endDate)
 | |
| 	failedCalls, _ := s.calcService.CalculateTotal(ctx, "api_calls", "failed_count", startDate, endDate)
 | |
| 	avgResponseTime, _ := s.calcService.CalculateAverage(ctx, "api_calls", "response_time", startDate, endDate)
 | |
| 
 | |
| 	content["total_calls"] = totalCalls
 | |
| 	content["success_calls"] = successCalls
 | |
| 	content["failed_calls"] = failedCalls
 | |
| 	content["success_rate"] = s.calculateRate(successCalls, totalCalls)
 | |
| 	content["avg_response_time"] = avgResponseTime
 | |
| 
 | |
| 	return content
 | |
| }
 | |
| 
 | |
| // generateUsersDetailedContent 生成用户详细内容
 | |
| func (s *StatisticsReportServiceImpl) generateUsersDetailedContent(ctx context.Context, startDate, endDate time.Time, filters map[string]interface{}) map[string]interface{} {
 | |
| 	content := make(map[string]interface{})
 | |
| 
 | |
| 	// 获取用户统计数据
 | |
| 	totalUsers, _ := s.calcService.CalculateTotal(ctx, "users", "total_count", startDate, endDate)
 | |
| 	certifiedUsers, _ := s.calcService.CalculateTotal(ctx, "users", "certified_count", startDate, endDate)
 | |
| 	activeUsers, _ := s.calcService.CalculateTotal(ctx, "users", "active_count", startDate, endDate)
 | |
| 
 | |
| 	content["total_users"] = totalUsers
 | |
| 	content["certified_users"] = certifiedUsers
 | |
| 	content["active_users"] = activeUsers
 | |
| 	content["certification_rate"] = s.calculateRate(certifiedUsers, totalUsers)
 | |
| 	content["retention_rate"] = s.calculateRate(activeUsers, totalUsers)
 | |
| 
 | |
| 	return content
 | |
| }
 | |
| 
 | |
| // generateFinanceDetailedContent 生成财务详细内容
 | |
| func (s *StatisticsReportServiceImpl) generateFinanceDetailedContent(ctx context.Context, startDate, endDate time.Time, filters map[string]interface{}) map[string]interface{} {
 | |
| 	content := make(map[string]interface{})
 | |
| 
 | |
| 	// 获取财务统计数据
 | |
| 	totalAmount, _ := s.calcService.CalculateTotal(ctx, "finance", "total_amount", startDate, endDate)
 | |
| 	rechargeAmount, _ := s.calcService.CalculateTotal(ctx, "finance", "recharge_amount", startDate, endDate)
 | |
| 	deductAmount, _ := s.calcService.CalculateTotal(ctx, "finance", "deduct_amount", startDate, endDate)
 | |
| 
 | |
| 	content["total_amount"] = totalAmount
 | |
| 	content["recharge_amount"] = rechargeAmount
 | |
| 	content["deduct_amount"] = deductAmount
 | |
| 	content["net_amount"] = rechargeAmount - deductAmount
 | |
| 
 | |
| 	return content
 | |
| }
 | |
| 
 | |
| // calculateRate 计算比率
 | |
| func (s *StatisticsReportServiceImpl) calculateRate(numerator, denominator float64) float64 {
 | |
| 	if denominator == 0 {
 | |
| 		return 0
 | |
| 	}
 | |
| 	return (numerator / denominator) * 100
 | |
| }
 | |
| 
 | |
| // getRoleDisplayName 获取角色显示名称
 | |
| func (s *StatisticsReportServiceImpl) getRoleDisplayName(role string) string {
 | |
| 	roleNames := map[string]string{
 | |
| 		"admin":   "管理员",
 | |
| 		"user":    "用户",
 | |
| 		"manager": "经理",
 | |
| 		"analyst": "分析师",
 | |
| 	}
 | |
| 	if name, exists := roleNames[role]; exists {
 | |
| 		return name
 | |
| 	}
 | |
| 	return role
 | |
| }
 | |
| 
 | |
| // getPeriodDisplayName 获取周期显示名称
 | |
| func (s *StatisticsReportServiceImpl) getPeriodDisplayName(period string) string {
 | |
| 	periodNames := map[string]string{
 | |
| 		"today":   "今日",
 | |
| 		"week":    "本周",
 | |
| 		"month":   "本月",
 | |
| 		"quarter": "本季度",
 | |
| 		"year":    "本年",
 | |
| 	}
 | |
| 	if name, exists := periodNames[period]; exists {
 | |
| 		return name
 | |
| 	}
 | |
| 	return period
 | |
| }
 | |
| 
 |