Files
tyapi-server/internal/infrastructure/statistics/migrations/statistics_migration.go
2025-09-12 01:15:09 +08:00

558 lines
14 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 migrations
import (
"fmt"
"time"
"gorm.io/gorm"
"tyapi-server/internal/domains/statistics/entities"
)
// StatisticsMigration 统计模块数据迁移
type StatisticsMigration struct {
db *gorm.DB
}
// NewStatisticsMigration 创建统计模块数据迁移
func NewStatisticsMigration(db *gorm.DB) *StatisticsMigration {
return &StatisticsMigration{
db: db,
}
}
// Migrate 执行数据迁移
func (m *StatisticsMigration) Migrate() error {
fmt.Println("开始执行统计模块数据迁移...")
// 迁移统计指标表
err := m.migrateStatisticsMetrics()
if err != nil {
return fmt.Errorf("迁移统计指标表失败: %w", err)
}
// 迁移统计报告表
err = m.migrateStatisticsReports()
if err != nil {
return fmt.Errorf("迁移统计报告表失败: %w", err)
}
// 迁移统计仪表板表
err = m.migrateStatisticsDashboards()
if err != nil {
return fmt.Errorf("迁移统计仪表板表失败: %w", err)
}
// 创建索引
err = m.createIndexes()
if err != nil {
return fmt.Errorf("创建索引失败: %w", err)
}
// 插入初始数据
err = m.insertInitialData()
if err != nil {
return fmt.Errorf("插入初始数据失败: %w", err)
}
fmt.Println("统计模块数据迁移完成")
return nil
}
// migrateStatisticsMetrics 迁移统计指标表
func (m *StatisticsMigration) migrateStatisticsMetrics() error {
fmt.Println("迁移统计指标表...")
// 自动迁移表结构
err := m.db.AutoMigrate(&entities.StatisticsMetric{})
if err != nil {
return fmt.Errorf("自动迁移统计指标表失败: %w", err)
}
fmt.Println("统计指标表迁移完成")
return nil
}
// migrateStatisticsReports 迁移统计报告表
func (m *StatisticsMigration) migrateStatisticsReports() error {
fmt.Println("迁移统计报告表...")
// 自动迁移表结构
err := m.db.AutoMigrate(&entities.StatisticsReport{})
if err != nil {
return fmt.Errorf("自动迁移统计报告表失败: %w", err)
}
fmt.Println("统计报告表迁移完成")
return nil
}
// migrateStatisticsDashboards 迁移统计仪表板表
func (m *StatisticsMigration) migrateStatisticsDashboards() error {
fmt.Println("迁移统计仪表板表...")
// 自动迁移表结构
err := m.db.AutoMigrate(&entities.StatisticsDashboard{})
if err != nil {
return fmt.Errorf("自动迁移统计仪表板表失败: %w", err)
}
fmt.Println("统计仪表板表迁移完成")
return nil
}
// createIndexes 创建索引
func (m *StatisticsMigration) 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 *StatisticsMigration) createStatisticsMetricsIndexes() error {
// 复合索引metric_type + date
err := m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_date
ON statistics_metrics (metric_type, date)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 复合索引metric_type + dimension + date
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_dimension_date
ON statistics_metrics (metric_type, dimension, date)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 复合索引metric_type + metric_name + date
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_metrics_type_name_date
ON statistics_metrics (metric_type, metric_name, date)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 单列索引dimension
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_metrics_dimension
ON statistics_metrics (dimension)
`).Error
if err != nil {
return fmt.Errorf("创建维度索引失败: %w", err)
}
return nil
}
// createStatisticsReportsIndexes 创建统计报告表索引
func (m *StatisticsMigration) createStatisticsReportsIndexes() error {
// 复合索引report_type + created_at
err := m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_reports_type_created
ON statistics_reports (report_type, created_at)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 复合索引user_role + created_at
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_reports_role_created
ON statistics_reports (user_role, created_at)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 复合索引status + created_at
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_reports_status_created
ON statistics_reports (status, created_at)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 单列索引generated_by
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_reports_generated_by
ON statistics_reports (generated_by)
`).Error
if err != nil {
return fmt.Errorf("创建生成者索引失败: %w", err)
}
// 单列索引expires_at
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_reports_expires_at
ON statistics_reports (expires_at)
`).Error
if err != nil {
return fmt.Errorf("创建过期时间索引失败: %w", err)
}
return nil
}
// createStatisticsDashboardsIndexes 创建统计仪表板表索引
func (m *StatisticsMigration) createStatisticsDashboardsIndexes() error {
// 复合索引user_role + is_active
err := m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_role_active
ON statistics_dashboards (user_role, is_active)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 复合索引user_role + is_default
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_role_default
ON statistics_dashboards (user_role, is_default)
`).Error
if err != nil {
return fmt.Errorf("创建复合索引失败: %w", err)
}
// 单列索引created_by
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_created_by
ON statistics_dashboards (created_by)
`).Error
if err != nil {
return fmt.Errorf("创建创建者索引失败: %w", err)
}
// 单列索引access_level
err = m.db.Exec(`
CREATE INDEX IF NOT EXISTS idx_statistics_dashboards_access_level
ON statistics_dashboards (access_level)
`).Error
if err != nil {
return fmt.Errorf("创建访问级别索引失败: %w", err)
}
return nil
}
// insertInitialData 插入初始数据
func (m *StatisticsMigration) 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 *StatisticsMigration) insertDefaultDashboards() error {
// 管理员默认仪表板
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 *StatisticsMigration) insertInitialMetrics() error {
now := time.Now()
today := now.Truncate(24 * time.Hour)
// 插入初始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,
},
}
// 插入初始用户指标
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,
},
}
// 插入初始财务指标
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,
},
}
// 插入初始产品指标
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,
},
}
// 插入初始认证指标
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,
},
}
// 批量插入所有指标
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 *StatisticsMigration) 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
}