package database import ( "backend/internal/model" "backend/utils" "log" "time" "gorm.io/gorm" ) const ( defaultAdminUsername = "admin" defaultAdminPassword = "admin" ) // SeedDefaults 初始化默认数据:管理员账号 + 系统设置 + 示例业务数据 // Logan.Li func SeedDefaults(db *gorm.DB) error { if err := seedAdmin(db); err != nil { return err } if err := seedSetting(db); err != nil { return err } if err := seedSampleData(db); err != nil { return err } if err := ensureOpsXShellPlanPricing(db); err != nil { return err } if err := ensureWaffoPaymentGateway(db); err != nil { return err } return nil } // seedAdmin 初始化默认管理员账号(仅在不存在时创建) // Logan.Li func seedAdmin(db *gorm.DB) error { var count int64 db.Model(&model.User{}).Where("username = ?", defaultAdminUsername).Count(&count) if count > 0 { return nil } admin := model.User{ Username: defaultAdminUsername, Password: utils.HashPassword(defaultAdminPassword), Email: "admin@opsx-licence.local", Role: "admin", IsActive: true, } if err := db.Create(&admin).Error; err != nil { return err } log.Printf("[初始化] 已创建默认管理员账号: %s / %s(请尽快修改密码)", defaultAdminUsername, defaultAdminPassword) return nil } // seedSetting 初始化默认系统设置(仅创建一次) // Logan.Li func seedSetting(db *gorm.DB) error { var count int64 db.Model(&model.Setting{}).Count(&count) if count > 0 { return nil } setting := model.Setting{ SystemName: "opsx-licence", DefaultDuration: 365, DefaultMaxActivations: 1, ExpireReminderDays: 7, APIRateLimit: 1000, LogRetentionDays: 365, } if err := db.Create(&setting).Error; err != nil { return err } log.Println("[初始化] 已创建默认系统设置") return nil } // seedSampleData 初始化 OpsXShell 产品 / 计划 / Waffo 网关,便于桌面端联调 // Logan.Li func seedSampleData(db *gorm.DB) error { var productCount int64 db.Model(&model.Product{}).Count(&productCount) if productCount > 0 { return nil } product := model.Product{ Name: "OpsXShell", Code: "opsxshell", Version: "2.0.0", Description: "OpsXShell Pro — SSH / SFTP / RDP / VNC / AI", Features: `["ssh","sftp","rdp","vnc","ai","portForward","proxy","serial","batchExec"]`, Price: 199.00, PriceModel: "perpetual", Status: 1, } if err := db.Create(&product).Error; err != nil { return err } customer := model.Customer{ Name: "Demo", Company: "OpsX", Email: "demo@opsxshell.local", Status: 1, } if err := db.Create(&customer).Error; err != nil { return err } plans := []model.Plan{ { ProductID: product.ID, Name: "体验", PlanType: "trial", Price: 0, Currency: "CNY", Duration: 180, MaxDevices: 1, Features: `["专业功能","体验","1 设备"]`, SortOrder: 0, Status: 1, }, { ProductID: product.ID, Name: "包年", PlanType: "yearly", Price: 99, Currency: "CNY", Duration: 365, MaxDevices: 2, Features: `["专业功能","包年","2 设备"]`, SortOrder: 1, Status: 1, }, { ProductID: product.ID, Name: "永久", PlanType: "perpetual", Price: 199, Currency: "CNY", Duration: 0, MaxDevices: 5, Features: `["专业功能","永久授权","5 设备"]`, SortOrder: 2, Status: 1, }, } for i := range plans { if err := db.Create(&plans[i]).Error; err != nil { return err } } now := time.Now() license := model.License{ LicenseKey: utils.GenerateLicenseKey(), CustomerID: customer.ID, ProductID: product.ID, Status: model.LicenseStatusActive, StartDate: now, EndDate: model.PermanentEndDate, Duration: 0, MaxActivations: 5, Notes: "开发示例授权", } if err := db.Create(&license).Error; err != nil { return err } gateway := model.PaymentGatewayConfig{ Gateway: "waffo", Enabled: true, SandboxMode: true, Currency: "USD", Priority: 1, } if err := db.Create(&gateway).Error; err != nil { return err } log.Printf("[初始化] OpsXShell 产品已就绪 (code=opsxshell),示例 License: %s", license.LicenseKey) return nil } // ensureOpsXShellPlanPricing ensures opsxshell product exists and syncs plan price/seats. // Logan.Li func ensureOpsXShellPlanPricing(db *gorm.DB) error { var product model.Product err := db.Where("code = ?", "opsxshell").First(&product).Error if err != nil { // Prefer renaming legacy demo product so existing plans/licenses stay attached. if renameErr := db.Where("code = ?", "opsx-tools").First(&product).Error; renameErr == nil { product.Code = "opsxshell" product.Name = "OpsXShell" product.Description = "OpsXShell Pro — SSH / SFTP / RDP / VNC / AI" product.Features = `["ssh","sftp","rdp","vnc","ai","portForward","proxy","serial","batchExec"]` product.Price = 199 product.PriceModel = "perpetual" product.Status = 1 if err := db.Save(&product).Error; err != nil { return err } log.Println("[初始化] 已将 opsx-tools 迁移为 opsxshell") } else { product = model.Product{ Name: "OpsXShell", Code: "opsxshell", Version: "2.0.0", Description: "OpsXShell Pro — SSH / SFTP / RDP / VNC / AI", Features: `["ssh","sftp","rdp","vnc","ai","portForward","proxy","serial","batchExec"]`, Price: 199, PriceModel: "perpetual", Status: 1, } if err := db.Create(&product).Error; err != nil { return err } log.Println("[初始化] 已创建 opsxshell 产品") } } type planSpec struct { planType string name string price float64 currency string duration int maxDevices int features string sortOrder int } updates := []planSpec{ {"trial", "体验", 0, "CNY", 180, 1, "[\"专业功能\",\"体验\",\"1 设备\"]", 0}, {"yearly", "包年", 99, "CNY", 365, 2, "[\"专业功能\",\"包年\",\"2 设备\"]", 1}, {"perpetual", "永久", 199, "CNY", 0, 5, "[\"专业功能\",\"永久授权\",\"5 设备\"]", 2}, } for _, u := range updates { var plan model.Plan err := db.Where("product_id = ? AND plan_type = ?", product.ID, u.planType).First(&plan).Error if err == nil { continue // 已存在:尊重管理员运行时修改,不再覆盖 // Logan.Li } plan = model.Plan{ ProductID: product.ID, Name: u.name, PlanType: u.planType, Price: u.price, Currency: u.currency, Duration: u.duration, MaxDevices: u.maxDevices, Features: u.features, SortOrder: u.sortOrder, Status: 1, } if err := db.Create(&plan).Error; err != nil { return err } } log.Printf("[初始化] OpsXShell 套餐已确保存在(仅新建,不覆盖已有价格)") return nil } // ensureWaffoPaymentGateway makes pancake.waffo.ai the preferred checkout gateway. // Logan.Li func ensureWaffoPaymentGateway(db *gorm.DB) error { var existing model.PaymentGatewayConfig err := db.Where("gateway = ?", "waffo").First(&existing).Error if err != nil { gw := model.PaymentGatewayConfig{ Gateway: "waffo", Enabled: true, SandboxMode: true, Currency: "CNY", Priority: 0, } if err := db.Create(&gw).Error; err != nil { return err } log.Println("[初始化] 已创建 Waffo 支付网关(默认沙箱,可在后台改 live)") } // 已存在则不覆盖 Enabled/SandboxMode,尊重管理员配置 // Logan.Li if err := db.Model(&model.PaymentGatewayConfig{}). Where("gateway <> ? AND enabled = ?", "waffo", true). Update("priority", 100).Error; err != nil { return err } return nil }