591 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			591 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package migrations
 | ||
| 
 | ||
| import (
 | ||
| 	"fmt"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	"gorm.io/gorm"
 | ||
| 
 | ||
| 	"tyapi-server/internal/domains/statistics/entities"
 | ||
| )
 | ||
| 
 | ||
| // StatisticsMigrationComplete 统计模块完整数据迁移
 | ||
| type StatisticsMigrationComplete struct {
 | ||
| 	db *gorm.DB
 | ||
| }
 | ||
| 
 | ||
| // NewStatisticsMigrationComplete 创建统计模块完整数据迁移
 | ||
| func NewStatisticsMigrationComplete(db *gorm.DB) *StatisticsMigrationComplete {
 | ||
| 	return &StatisticsMigrationComplete{
 | ||
| 		db: db,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // Migrate 执行完整的数据迁移
 | ||
| func (m *StatisticsMigrationComplete) Migrate() error {
 | ||
| 	fmt.Println("开始执行统计模块完整数据迁移...")
 | ||
| 
 | ||
| 	// 1. 迁移表结构
 | ||
| 	err := m.migrateTables()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("迁移表结构失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 2. 创建索引
 | ||
| 	err = m.createIndexes()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建索引失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 3. 插入初始数据
 | ||
| 	err = m.insertInitialData()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("插入初始数据失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("统计模块完整数据迁移完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // migrateTables 迁移表结构
 | ||
| func (m *StatisticsMigrationComplete) migrateTables() error {
 | ||
| 	fmt.Println("迁移统计模块表结构...")
 | ||
| 
 | ||
| 	// 迁移统计指标表
 | ||
| 	err := m.db.AutoMigrate(&entities.StatisticsMetric{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("迁移统计指标表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 迁移统计报告表
 | ||
| 	err = m.db.AutoMigrate(&entities.StatisticsReport{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("迁移统计报告表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 迁移统计仪表板表
 | ||
| 	err = m.db.AutoMigrate(&entities.StatisticsDashboard{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("迁移统计仪表板表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("统计模块表结构迁移完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // createIndexes 创建索引
 | ||
| func (m *StatisticsMigrationComplete) createIndexes() error {
 | ||
| 	fmt.Println("创建统计模块索引...")
 | ||
| 
 | ||
| 	// 统计指标表索引
 | ||
| 	err := m.createStatisticsMetricsIndexes()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建统计指标表索引失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 统计报告表索引
 | ||
| 	err = m.createStatisticsReportsIndexes()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建统计报告表索引失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 统计仪表板表索引
 | ||
| 	err = m.createStatisticsDashboardsIndexes()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建统计仪表板表索引失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("统计模块索引创建完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // createStatisticsMetricsIndexes 创建统计指标表索引
 | ||
| func (m *StatisticsMigrationComplete) createStatisticsMetricsIndexes() error {
 | ||
| 	indexes := []string{
 | ||
| 		// 复合索引:metric_type + date
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_date 
 | ||
| 		 ON statistics_metrics (metric_type, date)`,
 | ||
| 		
 | ||
| 		// 复合索引:metric_type + dimension + date
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_dimension_date 
 | ||
| 		 ON statistics_metrics (metric_type, dimension, date)`,
 | ||
| 		
 | ||
| 		// 复合索引:metric_type + metric_name + date
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_name_date 
 | ||
| 		 ON statistics_metrics (metric_type, metric_name, date)`,
 | ||
| 		
 | ||
| 		// 单列索引:dimension
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_dimension 
 | ||
| 		 ON statistics_metrics (dimension)`,
 | ||
| 		
 | ||
| 		// 单列索引:metric_name
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_name 
 | ||
| 		 ON statistics_metrics (metric_name)`,
 | ||
| 		
 | ||
| 		// 单列索引:value(用于范围查询)
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_metrics_value 
 | ||
| 		 ON statistics_metrics (value)`,
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, indexSQL := range indexes {
 | ||
| 		err := m.db.Exec(indexSQL).Error
 | ||
| 		if err != nil {
 | ||
| 			return fmt.Errorf("创建索引失败: %w", err)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // createStatisticsReportsIndexes 创建统计报告表索引
 | ||
| func (m *StatisticsMigrationComplete) createStatisticsReportsIndexes() error {
 | ||
| 	indexes := []string{
 | ||
| 		// 复合索引:report_type + created_at
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_type_created 
 | ||
| 		 ON statistics_reports (report_type, created_at)`,
 | ||
| 		
 | ||
| 		// 复合索引:user_role + created_at
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_role_created 
 | ||
| 		 ON statistics_reports (user_role, created_at)`,
 | ||
| 		
 | ||
| 		// 复合索引:status + created_at
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_status_created 
 | ||
| 		 ON statistics_reports (status, created_at)`,
 | ||
| 		
 | ||
| 		// 单列索引:generated_by
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_generated_by 
 | ||
| 		 ON statistics_reports (generated_by)`,
 | ||
| 		
 | ||
| 		// 单列索引:expires_at
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_expires_at 
 | ||
| 		 ON statistics_reports (expires_at)`,
 | ||
| 		
 | ||
| 		// 单列索引:period
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_reports_period 
 | ||
| 		 ON statistics_reports (period)`,
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, indexSQL := range indexes {
 | ||
| 		err := m.db.Exec(indexSQL).Error
 | ||
| 		if err != nil {
 | ||
| 			return fmt.Errorf("创建索引失败: %w", err)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // createStatisticsDashboardsIndexes 创建统计仪表板表索引
 | ||
| func (m *StatisticsMigrationComplete) createStatisticsDashboardsIndexes() error {
 | ||
| 	indexes := []string{
 | ||
| 		// 复合索引:user_role + is_active
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_role_active 
 | ||
| 		 ON statistics_dashboards (user_role, is_active)`,
 | ||
| 		
 | ||
| 		// 复合索引:user_role + is_default
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_role_default 
 | ||
| 		 ON statistics_dashboards (user_role, is_default)`,
 | ||
| 		
 | ||
| 		// 单列索引:created_by
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_created_by 
 | ||
| 		 ON statistics_dashboards (created_by)`,
 | ||
| 		
 | ||
| 		// 单列索引:access_level
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_access_level 
 | ||
| 		 ON statistics_dashboards (access_level)`,
 | ||
| 		
 | ||
| 		// 单列索引:name(用于搜索)
 | ||
| 		`CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_name 
 | ||
| 		 ON statistics_dashboards (name)`,
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, indexSQL := range indexes {
 | ||
| 		err := m.db.Exec(indexSQL).Error
 | ||
| 		if err != nil {
 | ||
| 			return fmt.Errorf("创建索引失败: %w", err)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // insertInitialData 插入初始数据
 | ||
| func (m *StatisticsMigrationComplete) insertInitialData() error {
 | ||
| 	fmt.Println("插入统计模块初始数据...")
 | ||
| 
 | ||
| 	// 插入默认仪表板
 | ||
| 	err := m.insertDefaultDashboards()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("插入默认仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始指标数据
 | ||
| 	err = m.insertInitialMetrics()
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("插入初始指标数据失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("统计模块初始数据插入完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // insertDefaultDashboards 插入默认仪表板
 | ||
| func (m *StatisticsMigrationComplete) insertDefaultDashboards() error {
 | ||
| 	// 检查是否已存在默认仪表板
 | ||
| 	var count int64
 | ||
| 	err := m.db.Model(&entities.StatisticsDashboard{}).Where("is_default = ?", true).Count(&count).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("检查默认仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 如果已存在默认仪表板,跳过插入
 | ||
| 	if count > 0 {
 | ||
| 		fmt.Println("默认仪表板已存在,跳过插入")
 | ||
| 		return nil
 | ||
| 	}
 | ||
| 
 | ||
| 	// 管理员默认仪表板
 | ||
| 	adminDashboard := &entities.StatisticsDashboard{
 | ||
| 		Name:            "管理员仪表板",
 | ||
| 		Description:     "系统管理员专用仪表板,包含所有统计信息",
 | ||
| 		UserRole:        "admin",
 | ||
| 		IsDefault:       true,
 | ||
| 		IsActive:        true,
 | ||
| 		AccessLevel:     "private",
 | ||
| 		RefreshInterval: 300,
 | ||
| 		CreatedBy:       "system",
 | ||
| 		Layout:          `{"columns": 3, "rows": 4}`,
 | ||
| 		Widgets:         `[{"type": "api_calls", "position": {"x": 0, "y": 0}}, {"type": "users", "position": {"x": 1, "y": 0}}, {"type": "finance", "position": {"x": 2, "y": 0}}]`,
 | ||
| 		Settings:        `{"theme": "dark", "auto_refresh": true}`,
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Create(adminDashboard).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建管理员仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 用户默认仪表板
 | ||
| 	userDashboard := &entities.StatisticsDashboard{
 | ||
| 		Name:            "用户仪表板",
 | ||
| 		Description:     "普通用户专用仪表板,包含基础统计信息",
 | ||
| 		UserRole:        "user",
 | ||
| 		IsDefault:       true,
 | ||
| 		IsActive:        true,
 | ||
| 		AccessLevel:     "private",
 | ||
| 		RefreshInterval: 600,
 | ||
| 		CreatedBy:       "system",
 | ||
| 		Layout:          `{"columns": 2, "rows": 3}`,
 | ||
| 		Widgets:         `[{"type": "api_calls", "position": {"x": 0, "y": 0}}, {"type": "users", "position": {"x": 1, "y": 0}}]`,
 | ||
| 		Settings:        `{"theme": "light", "auto_refresh": false}`,
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Create(userDashboard).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建用户仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 经理默认仪表板
 | ||
| 	managerDashboard := &entities.StatisticsDashboard{
 | ||
| 		Name:            "经理仪表板",
 | ||
| 		Description:     "经理专用仪表板,包含管理相关统计信息",
 | ||
| 		UserRole:        "manager",
 | ||
| 		IsDefault:       true,
 | ||
| 		IsActive:        true,
 | ||
| 		AccessLevel:     "private",
 | ||
| 		RefreshInterval: 300,
 | ||
| 		CreatedBy:       "system",
 | ||
| 		Layout:          `{"columns": 3, "rows": 3}`,
 | ||
| 		Widgets:         `[{"type": "api_calls", "position": {"x": 0, "y": 0}}, {"type": "users", "position": {"x": 1, "y": 0}}, {"type": "finance", "position": {"x": 2, "y": 0}}]`,
 | ||
| 		Settings:        `{"theme": "dark", "auto_refresh": true}`,
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Create(managerDashboard).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建经理仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 分析师默认仪表板
 | ||
| 	analystDashboard := &entities.StatisticsDashboard{
 | ||
| 		Name:            "分析师仪表板",
 | ||
| 		Description:     "数据分析师专用仪表板,包含详细分析信息",
 | ||
| 		UserRole:        "analyst",
 | ||
| 		IsDefault:       true,
 | ||
| 		IsActive:        true,
 | ||
| 		AccessLevel:     "private",
 | ||
| 		RefreshInterval: 180,
 | ||
| 		CreatedBy:       "system",
 | ||
| 		Layout:          `{"columns": 4, "rows": 4}`,
 | ||
| 		Widgets:         `[{"type": "api_calls", "position": {"x": 0, "y": 0}}, {"type": "users", "position": {"x": 1, "y": 0}}, {"type": "finance", "position": {"x": 2, "y": 0}}, {"type": "products", "position": {"x": 3, "y": 0}}]`,
 | ||
| 		Settings:        `{"theme": "dark", "auto_refresh": true, "show_trends": true}`,
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Create(analystDashboard).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("创建分析师仪表板失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("默认仪表板创建完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // insertInitialMetrics 插入初始指标数据
 | ||
| func (m *StatisticsMigrationComplete) insertInitialMetrics() error {
 | ||
| 	now := time.Now()
 | ||
| 	today := now.Truncate(24 * time.Hour)
 | ||
| 
 | ||
| 	// 检查是否已存在今日指标数据
 | ||
| 	var count int64
 | ||
| 	err := m.db.Model(&entities.StatisticsMetric{}).Where("date = ?", today).Count(&count).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("检查指标数据失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 如果已存在今日指标数据,跳过插入
 | ||
| 	if count > 0 {
 | ||
| 		fmt.Println("今日指标数据已存在,跳过插入")
 | ||
| 		return nil
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始API调用指标
 | ||
| 	apiMetrics := []*entities.StatisticsMetric{
 | ||
| 		{
 | ||
| 			MetricType: "api_calls",
 | ||
| 			MetricName: "total_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "api_calls",
 | ||
| 			MetricName: "success_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "api_calls",
 | ||
| 			MetricName: "failed_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "api_calls",
 | ||
| 			MetricName: "response_time",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "api_calls",
 | ||
| 			MetricName: "avg_response_time",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始用户指标
 | ||
| 	userMetrics := []*entities.StatisticsMetric{
 | ||
| 		{
 | ||
| 			MetricType: "users",
 | ||
| 			MetricName: "total_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "users",
 | ||
| 			MetricName: "certified_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "users",
 | ||
| 			MetricName: "active_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "users",
 | ||
| 			MetricName: "new_users_today",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始财务指标
 | ||
| 	financeMetrics := []*entities.StatisticsMetric{
 | ||
| 		{
 | ||
| 			MetricType: "finance",
 | ||
| 			MetricName: "total_amount",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "finance",
 | ||
| 			MetricName: "recharge_amount",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "finance",
 | ||
| 			MetricName: "deduct_amount",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "finance",
 | ||
| 			MetricName: "recharge_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "finance",
 | ||
| 			MetricName: "deduct_count",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始产品指标
 | ||
| 	productMetrics := []*entities.StatisticsMetric{
 | ||
| 		{
 | ||
| 			MetricType: "products",
 | ||
| 			MetricName: "total_products",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "products",
 | ||
| 			MetricName: "active_products",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "products",
 | ||
| 			MetricName: "total_subscriptions",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "products",
 | ||
| 			MetricName: "active_subscriptions",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "products",
 | ||
| 			MetricName: "new_subscriptions_today",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	// 插入初始认证指标
 | ||
| 	certificationMetrics := []*entities.StatisticsMetric{
 | ||
| 		{
 | ||
| 			MetricType: "certification",
 | ||
| 			MetricName: "total_certifications",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "certification",
 | ||
| 			MetricName: "completed_certifications",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "certification",
 | ||
| 			MetricName: "pending_certifications",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "certification",
 | ||
| 			MetricName: "failed_certifications",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			MetricType: "certification",
 | ||
| 			MetricName: "certification_rate",
 | ||
| 			Dimension:  "realtime",
 | ||
| 			Value:      0,
 | ||
| 			Date:       today,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	// 批量插入所有指标
 | ||
| 	allMetrics := append(apiMetrics, userMetrics...)
 | ||
| 	allMetrics = append(allMetrics, financeMetrics...)
 | ||
| 	allMetrics = append(allMetrics, productMetrics...)
 | ||
| 	allMetrics = append(allMetrics, certificationMetrics...)
 | ||
| 
 | ||
| 	err = m.db.CreateInBatches(allMetrics, 100).Error
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("批量插入初始指标失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("初始指标数据创建完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // Rollback 回滚迁移
 | ||
| func (m *StatisticsMigrationComplete) Rollback() error {
 | ||
| 	fmt.Println("开始回滚统计模块数据迁移...")
 | ||
| 
 | ||
| 	// 删除表
 | ||
| 	err := m.db.Migrator().DropTable(&entities.StatisticsDashboard{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("删除统计仪表板表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Migrator().DropTable(&entities.StatisticsReport{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("删除统计报告表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	err = m.db.Migrator().DropTable(&entities.StatisticsMetric{})
 | ||
| 	if err != nil {
 | ||
| 		return fmt.Errorf("删除统计指标表失败: %w", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("统计模块数据迁移回滚完成")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // GetTableInfo 获取表信息
 | ||
| func (m *StatisticsMigrationComplete) GetTableInfo() map[string]interface{} {
 | ||
| 	info := make(map[string]interface{})
 | ||
| 
 | ||
| 	// 获取表统计信息
 | ||
| 	tables := []string{"statistics_metrics", "statistics_reports", "statistics_dashboards"}
 | ||
| 	
 | ||
| 	for _, table := range tables {
 | ||
| 		var count int64
 | ||
| 		m.db.Table(table).Count(&count)
 | ||
| 		info[table] = count
 | ||
| 	}
 | ||
| 
 | ||
| 	return info
 | ||
| }
 |