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
|
||
|
|
}
|
||
|
|
|