You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

246 lines
8.0 KiB

package migration
import (
"gofaster/internal/auth/model"
"regexp"
"go.uber.org/zap"
"gorm.io/gorm"
)
// CreateRouteTables 创建路由相关表
func CreateRouteTables(db *gorm.DB, log *zap.Logger) error {
log.Info("开始创建路由相关表...")
// 创建菜单表
if err := db.AutoMigrate(&model.Menu{}); err != nil {
log.Error("创建菜单表失败", zap.Error(err))
return err
}
log.Info("✅ 菜单表创建完成")
// 创建路由映射表
log.Info("🔧 开始创建route_mappings表...")
log.Info("📋 RouteMapping模型字段:",
zap.String("ID", "uint"),
zap.String("UpdatedAt", "time.Time"),
zap.String("BackendRoute", "string"),
zap.String("HTTPMethod", "string"),
zap.String("ResourceID", "*uint"),
zap.String("Module", "string"),
zap.String("Description", "string"),
zap.String("Status", "int"))
if err := db.AutoMigrate(&model.RouteMapping{}); err != nil {
log.Error("❌ 创建路由映射表失败", zap.Error(err))
return err
}
log.Info("✅ 路由映射表创建完成")
// 创建菜单路由关联表
if err := db.AutoMigrate(&model.MenuRoute{}); err != nil {
log.Error("创建菜单路由关联表失败", zap.Error(err))
return err
}
log.Info("✅ 菜单路由关联表创建完成")
// 创建前台路由表
if err := db.AutoMigrate(&model.FrontendRoute{}); err != nil {
log.Error("创建前台路由表失败", zap.Error(err))
return err
}
log.Info("✅ 前台路由表创建完成")
// 创建前后台路由关系表
if err := db.AutoMigrate(&model.FrontendBackendRoute{}); err != nil {
log.Error("创建前后台路由关系表失败", zap.Error(err))
return err
}
log.Info("✅ 前后台路由关系表创建完成")
// 为现有Resource表添加菜单相关字段
if err := addMenuFieldsToResource(db, log); err != nil {
log.Error("为Resource表添加菜单字段失败", zap.Error(err))
return err
}
log.Info("✅ Resource表菜单字段添加完成")
// 处理RouteMapping表的字段变更
if err := updateRouteMappingFields(db, log); err != nil {
log.Error("更新RouteMapping表字段失败", zap.Error(err))
return err
}
log.Info("✅ RouteMapping表字段更新完成")
log.Info("路由相关表创建完成")
return nil
}
// updateRouteMappingFields 更新RouteMapping表的字段
func updateRouteMappingFields(db *gorm.DB, log *zap.Logger) error {
log.Info("🔧 开始更新route_mappings表字段...")
// 检查表是否存在
var tableExists bool
err := db.Raw("SELECT COUNT(*) > 0 FROM information_schema.tables WHERE table_name = 'route_mappings'").Scan(&tableExists).Error
if err != nil {
log.Error("❌ 检查表是否存在失败", zap.Error(err))
return err
}
log.Info("📊 表存在状态检查", zap.Bool("tableExists", tableExists))
if !tableExists {
log.Info("⚠ route_mappings表不存在,跳过字段更新")
return nil
}
// 获取当前表结构
log.Info("📋 获取当前表结构...")
var columns []struct {
ColumnName string `gorm:"column:COLUMN_NAME"`
DataType string `gorm:"column:DATA_TYPE"`
}
if err := db.Raw("SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.columns WHERE table_name = 'route_mappings' ORDER BY ORDINAL_POSITION").Scan(&columns).Error; err != nil {
log.Error("❌ 获取表结构失败", zap.Error(err))
} else {
log.Info("📋 当前表结构:")
for _, col := range columns {
log.Info(" - " + col.ColumnName + " (" + col.DataType + ")")
}
}
// 删除不需要的字段
fieldsToRemove := []string{"created_at", "frontend_route", "auth_group", "menu_id"}
log.Info("🗑 准备删除字段", zap.Strings("fields", fieldsToRemove))
for _, field := range fieldsToRemove {
var hasField bool
err := db.Raw("SELECT COUNT(*) > 0 FROM information_schema.columns WHERE table_name = 'route_mappings' AND column_name = ?", field).Scan(&hasField).Error
if err != nil {
log.Warn("⚠ 检查字段失败", zap.String("field", field), zap.Error(err))
continue
}
log.Info("🔍 字段检查结果", zap.String("field", field), zap.Bool("exists", hasField))
if hasField {
// 删除字段
log.Info("🗑 执行DDL: ALTER TABLE route_mappings DROP COLUMN " + field)
if err := db.Exec("ALTER TABLE route_mappings DROP COLUMN " + field).Error; err != nil {
log.Warn("❌ 删除字段失败", zap.String("field", field), zap.Error(err))
} else {
log.Info("✅ 删除字段成功", zap.String("field", field))
}
} else {
log.Info("ℹ 字段不存在,跳过删除", zap.String("field", field))
}
}
// 更新现有记录的路径格式(将:var改为{var})
log.Info("🔄 开始更新路径格式...")
if err := updatePathFormat(db, log); err != nil {
log.Error("❌ 更新路径格式失败", zap.Error(err))
return err
}
log.Info("✅ route_mappings表字段更新完成")
return nil
}
// updatePathFormat 更新路径格式:将:var改为{var}
func updatePathFormat(db *gorm.DB, log *zap.Logger) error {
log.Info("🔍 查找需要更新路径格式的记录...")
// 获取所有需要更新的记录
var mappings []struct {
ID uint `gorm:"column:id"`
BackendRoute string `gorm:"column:backend_route"`
}
query := "SELECT id, backend_route FROM route_mappings WHERE backend_route LIKE '%:%'"
log.Info("📝 执行查询", zap.String("query", query))
if err := db.Raw(query).Scan(&mappings).Error; err != nil {
log.Error("❌ 查询需要更新的记录失败", zap.Error(err))
return err
}
log.Info("📊 找到需要更新路径格式的记录", zap.Int("count", len(mappings)))
if len(mappings) == 0 {
log.Info("ℹ 没有需要更新路径格式的记录")
return nil
}
// 更新每条记录
updatedCount := 0
for _, mapping := range mappings {
// 转换路径格式
newPath := convertPathFormat(mapping.BackendRoute)
log.Info("🔄 路径转换",
zap.Uint("id", mapping.ID),
zap.String("old", mapping.BackendRoute),
zap.String("new", newPath))
if newPath != mapping.BackendRoute {
updateQuery := "UPDATE route_mappings SET backend_route = ? WHERE id = ?"
log.Info("📝 执行更新", zap.String("query", updateQuery), zap.String("newPath", newPath), zap.Uint("id", mapping.ID))
if err := db.Exec(updateQuery, newPath, mapping.ID).Error; err != nil {
log.Error("❌ 更新路径失败", zap.Uint("id", mapping.ID), zap.Error(err))
} else {
log.Info("✅ 更新路径成功", zap.Uint("id", mapping.ID), zap.String("old", mapping.BackendRoute), zap.String("new", newPath))
updatedCount++
}
} else {
log.Info("ℹ 路径无需更新", zap.Uint("id", mapping.ID))
}
}
log.Info("📊 路径格式更新完成", zap.Int("total", len(mappings)), zap.Int("updated", updatedCount))
return nil
}
// convertPathFormat 转换路径格式:将:var格式改为{var}格式
func convertPathFormat(path string) string {
// 使用正则表达式替换:var格式为{var}格式
re := regexp.MustCompile(`:([a-zA-Z0-9_]+)`)
return re.ReplaceAllString(path, "{$1}")
}
// addMenuFieldsToResource 为Resource表添加菜单相关字段
func addMenuFieldsToResource(db *gorm.DB, log *zap.Logger) error {
// 检查IsMenu字段是否存在
var hasIsMenu bool
err := db.Raw("SELECT COUNT(*) > 0 FROM information_schema.columns WHERE table_name = 'resources' AND column_name = 'is_menu'").Scan(&hasIsMenu).Error
if err != nil {
return err
}
if !hasIsMenu {
// 添加IsMenu字段
if err := db.Exec("ALTER TABLE resources ADD COLUMN is_menu BOOLEAN DEFAULT FALSE").Error; err != nil {
return err
}
log.Info("添加is_menu字段到resources表")
}
// 移除旧的MenuID字段(如果存在)
var hasMenuID bool
err = db.Raw("SELECT COUNT(*) > 0 FROM information_schema.columns WHERE table_name = 'resources' AND column_name = 'menu_id'").Scan(&hasMenuID).Error
if err != nil {
return err
}
if hasMenuID {
// 删除MenuID字段
if err := db.Exec("ALTER TABLE resources DROP COLUMN menu_id").Error; err != nil {
log.Warn("删除menu_id字段失败,可能已被删除", zap.Error(err))
} else {
log.Info("删除menu_id字段从resources表")
}
}
return nil
}