// gencode — 平台方批量生成兑换券(激活码)并写入码池 license_codes。 // // 用法(在 backend/ 目录下执行,读 config/env 取数据库 DSN): // // go run ./cmd/gencode -type annual -days 365 -count 100 -batch 2026-summer // go run ./cmd/gencode -days 30 -count 10 -note "试用补偿" // go run ./cmd/gencode -type lifetime -days 0 -count 1 # 永久授权码 // // 生成的码以 JIUKU-XXXX-XXXX 格式打印(status=unused),分发给用户在 App 内兑换。 package main import ( "flag" "fmt" stdlog "log" "os" "time" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/wangjia/jiu/backend/config" "github.com/wangjia/jiu/backend/internal/model" "github.com/wangjia/jiu/backend/internal/util" ) func main() { licType := flag.String("type", "annual", "计费/时长标签:trial|monthly|annual|lifetime") tier := flag.String("tier", "standard", "档位(当前仅 standard)") days := flag.Int("days", 365, "授予时长(天);0 = 永久") devices := flag.Int("devices", 0, "授予设备上限;0 = 兑换时不改变门店现值") count := flag.Int("count", 1, "生成数量") batch := flag.String("batch", "", "发放批次/活动名(便于追踪)") note := flag.String("note", "", "备注") flag.Parse() if *count < 1 { fmt.Fprintln(os.Stderr, "error: -count 必须 >= 1") os.Exit(1) } config.Load() db, err := gorm.Open(mysql.Open(config.C.Database.DSN), &gorm.Config{ Logger: logger.New( stdlog.New(os.Stdout, "\r\n", stdlog.LstdFlags), logger.Config{LogLevel: logger.Warn, IgnoreRecordNotFoundError: true}, ), }) if err != nil { stdlog.Fatalf("连接数据库失败: %v", err) } if err := db.AutoMigrate(&model.LicenseCode{}); err != nil { stdlog.Fatalf("迁移 license_codes 失败: %v", err) } display := make([]string, 0, *count) for i := 0; i < *count; i++ { // 重试避免极小概率的唯一冲突 var shown string for attempt := 0; attempt < 5; attempt++ { shown = util.GenerateRedeemCode() lc := model.LicenseCode{ Code: util.NormalizeCode(shown), Type: *licType, Tier: *tier, DurationDays: *days, MaxDevices: *devices, Status: "unused", Batch: *batch, Note: *note, } err := db.Create(&lc).Error if err == nil { break } if attempt == 4 { stdlog.Fatalf("写入兑换码失败(连续冲突): %v", err) } } display = append(display, shown) } fmt.Printf("\n✅ 已生成 %d 个兑换码(type=%s tier=%s 时长=%d天 设备=%d batch=%q)于 %s:\n\n", *count, *licType, *tier, *days, *devices, *batch, time.Now().Format("2006-01-02 15:04:05")) for _, c := range display { fmt.Println(" " + c) } fmt.Println() }