This commit is contained in:
2025-09-12 01:15:09 +08:00
parent c563b2266b
commit e05ad9e223
103 changed files with 20034 additions and 1041 deletions

View File

@@ -0,0 +1,557 @@
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
}