From 6788d49f478a18ebb69a1dc4973e44cc8ff7c6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Mon, 15 Jun 2026 23:43:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BB=AD=E6=9D=AF=E6=BF=80?= =?UTF-8?q?=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform_cursor_activation_code.go | 750 ++++++++++++++++++ .../yz_platform_cursor_activation_code.sql | 31 + models/init.go | 1 + models/platform_cursor_activation_code.go | 28 + routers/platform/platform.go | 11 + 5 files changed, 821 insertions(+) create mode 100644 controllers/platform_cursor_activation_code.go create mode 100644 docs/sql/yz_platform_cursor_activation_code.sql create mode 100644 models/platform_cursor_activation_code.go diff --git a/controllers/platform_cursor_activation_code.go b/controllers/platform_cursor_activation_code.go new file mode 100644 index 0000000..110f0f6 --- /dev/null +++ b/controllers/platform_cursor_activation_code.go @@ -0,0 +1,750 @@ +package controllers + +import ( + "crypto/rand" + "encoding/csv" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "time" + + "server/models" + "server/pkg/jwtutil" + + "github.com/beego/beego/v2/client/orm" + beego "github.com/beego/beego/v2/server/web" +) + +// PlatformCursorActivationCodeController 平台端 Cursor 激活码管理 +type PlatformCursorActivationCodeController struct { + beego.Controller +} + +func (c *PlatformCursorActivationCodeController) platformClaims() (*jwtutil.Claims, error) { + auth := c.Ctx.Request.Header.Get("Authorization") + if auth == "" { + return nil, fmt.Errorf("未登录") + } + parts := strings.SplitN(auth, " ", 2) + if len(parts) != 2 || parts[0] != "Bearer" { + return nil, fmt.Errorf("认证信息格式错误") + } + claims, err := jwtutil.ParseToken(parts[1]) + if err != nil { + return nil, fmt.Errorf("无效的token") + } + if claims.UserType != "platform" { + return nil, fmt.Errorf("无权访问") + } + return claims, nil +} + +func (c *PlatformCursorActivationCodeController) jsonErr(httpStatus, bizCode int, msg string) { + c.Ctx.Output.SetStatus(httpStatus) + c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg} + _ = c.ServeJSON() +} + +func (c *PlatformCursorActivationCodeController) ok(data interface{}) { + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data} + _ = c.ServeJSON() +} + +func cursorActivationCodeTrimPtr(value *string) *string { + if value == nil { + return nil + } + v := strings.TrimSpace(*value) + if v == "" { + return nil + } + return &v +} + +func cursorActivationCodeTimePtr(value *string) *time.Time { + if value == nil { + return nil + } + v := strings.TrimSpace(*value) + if v == "" { + return nil + } + layouts := []string{ + time.RFC3339, + "2006-01-02 15:04:05", + "2006-01-02 15:04", + "2006-01-02", + } + for _, layout := range layouts { + if t, err := time.ParseInLocation(layout, v, time.Local); err == nil { + return &t + } + } + return nil +} + +func cursorActivationCodeStatusValid(status int8) bool { + return status == 0 || status == 1 || status == 2 || status == 3 +} + +func cursorActivationCodeTypeName(cardType int) string { + switch cardType { + case 1: + return "天卡" + case 7: + return "周卡" + case 30: + return "月卡" + case 90: + return "季卡" + case 365: + return "年卡" + case 0: + return "自定义" + default: + return fmt.Sprintf("%d天", cardType) + } +} + +func (c *PlatformCursorActivationCodeController) rowToMap(row *models.PlatformCursorActivationCode) map[string]interface{} { + bindStatus := 0 + if row.BindAccount != nil || row.BindDeviceID != nil || row.MachineCode != nil { + bindStatus = 1 + } + + return map[string]interface{}{ + "id": row.ID, + "code": row.Code, + "type": row.Type, + "typeName": cursorActivationCodeTypeName(row.Type), + "status": row.Status, + "durationDays": row.DurationDays, + "bindAccount": row.BindAccount, + "bindDeviceId": row.BindDeviceID, + "bindStatus": bindStatus, + "machineCode": row.MachineCode, + "deviceInfo": row.DeviceInfo, + "ownerUserId": row.OwnerUserID, + "ownerUserName": row.OwnerUserName, + "activatedAt": row.ActivatedAt, + "expiredAt": row.ExpiredAt, + "createdAt": row.CreateTime, + "updatedAt": row.UpdateTime, + "createTime": row.CreateTime, + "updateTime": row.UpdateTime, + "remark": row.Remark, + } +} + +func (c *PlatformCursorActivationCodeController) filteredQuery() orm.QuerySeter { + keyword := strings.TrimSpace(c.GetString("keyword")) + statusText := strings.TrimSpace(c.GetString("status")) + typeText := strings.TrimSpace(c.GetString("type")) + bindStatusText := strings.TrimSpace(c.GetString("bindStatus")) + + qs := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).Filter("delete_time__isnull", true) + + if keyword != "" { + cond := orm.NewCondition(). + Or("code__icontains", keyword). + Or("bind_account__icontains", keyword). + Or("machine_code__icontains", keyword). + Or("device_info__icontains", keyword). + Or("owner_user_name__icontains", keyword). + Or("remark__icontains", keyword) + qs = qs.SetCond(cond) + qs = qs.Filter("delete_time__isnull", true) + } + + if statusText != "" { + status, err := strconv.ParseInt(statusText, 10, 8) + if err == nil && cursorActivationCodeStatusValid(int8(status)) { + qs = qs.Filter("status", int8(status)) + } + } + + if typeText != "" { + cardType, err := strconv.Atoi(typeText) + if err == nil { + qs = qs.Filter("type", cardType) + } + } + + if bindStatusText != "" { + bindStatus, err := strconv.Atoi(bindStatusText) + if err == nil { + if bindStatus == 0 { + qs = qs.Filter("bind_account__isnull", true).Filter("bind_device_id__isnull", true).Filter("machine_code__isnull", true) + } else if bindStatus == 1 { + cond := orm.NewCondition(). + Or("bind_account__isnull", false). + Or("bind_device_id__isnull", false). + Or("machine_code__isnull", false) + qs = qs.SetCond(cond) + qs = qs.Filter("delete_time__isnull", true) + if statusText != "" { + status, err := strconv.ParseInt(statusText, 10, 8) + if err == nil && cursorActivationCodeStatusValid(int8(status)) { + qs = qs.Filter("status", int8(status)) + } + } + if typeText != "" { + cardType, err := strconv.Atoi(typeText) + if err == nil { + qs = qs.Filter("type", cardType) + } + } + } + } + } + + return qs +} + +// List GET /platform/cursor/activationcode/list +func (c *PlatformCursorActivationCodeController) List() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + page, _ := c.GetInt("page", 1) + pageSize, _ := c.GetInt("pageSize", 20) + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 20 + } + if pageSize > 200 { + pageSize = 200 + } + + qs := c.filteredQuery() + total, _ := qs.Count() + + var rows []models.PlatformCursorActivationCode + _, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows) + if err != nil { + c.jsonErr(500, 500, "获取激活码列表失败: "+err.Error()) + return + } + + list := make([]map[string]interface{}, 0, len(rows)) + for i := range rows { + list = append(list, c.rowToMap(&rows[i])) + } + + c.ok(map[string]interface{}{ + "list": list, + "total": total, + "page": page, + "pageSize": pageSize, + }) +} + +// Detail GET /platform/cursor/activationcode/detail/:id +func (c *PlatformCursorActivationCodeController) Detail() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) + if err != nil || id == 0 { + c.jsonErr(400, 400, "无效ID") + return + } + + var row models.PlatformCursorActivationCode + err = models.Orm.QueryTable(new(models.PlatformCursorActivationCode)). + Filter("id", id). + Filter("delete_time__isnull", true). + One(&row) + if err != nil { + c.jsonErr(404, 404, "激活码不存在") + return + } + + c.ok(c.rowToMap(&row)) +} + +type platformCursorActivationCodePayload struct { + ID *uint64 `json:"id"` + Code *string `json:"code"` + Type *int `json:"type"` + Status *int8 `json:"status"` + DurationDays *int `json:"durationDays"` + BindAccount *string `json:"bindAccount"` + BindDeviceID *uint64 `json:"bindDeviceId"` + OwnerUserID *uint64 `json:"ownerUserId"` + OwnerUserName *string `json:"ownerUserName"` + ActivatedAt *string `json:"activatedAt"` + ExpiredAt *string `json:"expiredAt"` + Remark *string `json:"remark"` +} + +func (c *PlatformCursorActivationCodeController) readPayload() (*platformCursorActivationCodePayload, error) { + body, _ := io.ReadAll(c.Ctx.Request.Body) + var p platformCursorActivationCodePayload + if err := json.Unmarshal(body, &p); err != nil { + return nil, err + } + return &p, nil +} + +func (c *PlatformCursorActivationCodeController) fillDeviceSnapshot(up map[string]interface{}, bindDeviceID *uint64) { + if bindDeviceID == nil || *bindDeviceID == 0 { + up["bind_device_id"] = nil + up["machine_code"] = nil + up["device_info"] = nil + return + } + + var device models.PlatformCursorEquipment + err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)). + Filter("id", *bindDeviceID). + Filter("delete_time__isnull", true). + One(&device) + if err == nil { + up["bind_device_id"] = *bindDeviceID + up["machine_code"] = device.MachineCode + up["device_info"] = device.DeviceInfo + return + } + + up["bind_device_id"] = *bindDeviceID +} + +func (c *PlatformCursorActivationCodeController) payloadToUpdateMap(p *platformCursorActivationCodePayload, includeCode bool) (map[string]interface{}, error) { + up := map[string]interface{}{} + + if includeCode { + if p.Code == nil || strings.TrimSpace(*p.Code) == "" { + return nil, fmt.Errorf("激活码不能为空") + } + up["code"] = strings.TrimSpace(*p.Code) + } else if p.Code != nil { + if strings.TrimSpace(*p.Code) == "" { + return nil, fmt.Errorf("激活码不能为空") + } + up["code"] = strings.TrimSpace(*p.Code) + } + + if p.Type != nil { + if *p.Type < 0 { + return nil, fmt.Errorf("卡密类型不合法") + } + up["type"] = *p.Type + } + if p.Status != nil { + if !cursorActivationCodeStatusValid(*p.Status) { + return nil, fmt.Errorf("状态不合法,支持:0 未使用、1 已使用、2 已过期、3 已禁用") + } + up["status"] = *p.Status + } + if p.DurationDays != nil { + if *p.DurationDays < 0 || *p.DurationDays > 9999 { + return nil, fmt.Errorf("有效天数范围为 0-9999") + } + up["duration_days"] = *p.DurationDays + } + if p.BindAccount != nil { + up["bind_account"] = cursorActivationCodeTrimPtr(p.BindAccount) + } + if p.BindDeviceID != nil { + c.fillDeviceSnapshot(up, p.BindDeviceID) + } + if p.OwnerUserID != nil { + if *p.OwnerUserID == 0 { + up["owner_user_id"] = nil + } else { + up["owner_user_id"] = *p.OwnerUserID + } + } + if p.OwnerUserName != nil { + up["owner_user_name"] = cursorActivationCodeTrimPtr(p.OwnerUserName) + } + if p.ActivatedAt != nil { + up["activated_at"] = cursorActivationCodeTimePtr(p.ActivatedAt) + } + if p.ExpiredAt != nil { + up["expired_at"] = cursorActivationCodeTimePtr(p.ExpiredAt) + } + if p.Remark != nil { + up["remark"] = cursorActivationCodeTrimPtr(p.Remark) + } + + return up, nil +} + +// Add POST /platform/cursor/activationcode/add +func (c *PlatformCursorActivationCodeController) Add() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + p, err := c.readPayload() + if err != nil { + c.jsonErr(400, 400, "参数错误") + return + } + + up, err := c.payloadToUpdateMap(p, true) + if err != nil { + c.jsonErr(400, 400, err.Error()) + return + } + + row := models.PlatformCursorActivationCode{ + Code: up["code"].(string), + Type: 30, + Status: 0, + DurationDays: 30, + BindAccount: cursorActivationCodeTrimPtr(p.BindAccount), + BindDeviceID: p.BindDeviceID, + OwnerUserID: p.OwnerUserID, + OwnerUserName: cursorActivationCodeTrimPtr(p.OwnerUserName), + ActivatedAt: cursorActivationCodeTimePtr(p.ActivatedAt), + ExpiredAt: cursorActivationCodeTimePtr(p.ExpiredAt), + Remark: cursorActivationCodeTrimPtr(p.Remark), + CreateTime: time.Now(), + } + + if p.Type != nil { + row.Type = *p.Type + } + if p.Status != nil { + row.Status = *p.Status + } + if p.DurationDays != nil { + row.DurationDays = *p.DurationDays + } + if row.BindDeviceID != nil && *row.BindDeviceID == 0 { + row.BindDeviceID = nil + } + if row.OwnerUserID != nil && *row.OwnerUserID == 0 { + row.OwnerUserID = nil + } + if row.BindDeviceID != nil { + var device models.PlatformCursorEquipment + if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)). + Filter("id", *row.BindDeviceID). + Filter("delete_time__isnull", true). + One(&device); err == nil { + row.MachineCode = &device.MachineCode + row.DeviceInfo = device.DeviceInfo + } + } + + id, err := models.Orm.Insert(&row) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), "duplicate") { + c.jsonErr(400, 400, "激活码已存在") + return + } + c.jsonErr(500, 500, "新增激活码失败: "+err.Error()) + return + } + + c.ok(map[string]interface{}{"id": id}) +} + +// Update POST /platform/cursor/activationcode/update +func (c *PlatformCursorActivationCodeController) Update() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + p, err := c.readPayload() + if err != nil { + c.jsonErr(400, 400, "参数错误") + return + } + if p.ID == nil || *p.ID == 0 { + c.jsonErr(400, 400, "无效ID") + return + } + + up, err := c.payloadToUpdateMap(p, false) + if err != nil { + c.jsonErr(400, 400, err.Error()) + return + } + if len(up) == 0 { + c.jsonErr(400, 400, "无更新字段") + return + } + + now := time.Now() + up["update_time"] = now + + n, err := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)). + Filter("id", *p.ID). + Filter("delete_time__isnull", true). + Update(up) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), "duplicate") { + c.jsonErr(400, 400, "激活码已存在") + return + } + c.jsonErr(500, 500, "更新激活码失败: "+err.Error()) + return + } + if n == 0 { + c.jsonErr(404, 404, "激活码不存在") + return + } + + c.ok(nil) +} + +// Delete POST /platform/cursor/activationcode/delete/:id +func (c *PlatformCursorActivationCodeController) Delete() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) + if err != nil || id == 0 { + c.jsonErr(400, 400, "无效ID") + return + } + + now := time.Now() + n, err := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)). + Filter("id", id). + Filter("delete_time__isnull", true). + Update(map[string]interface{}{"delete_time": now, "update_time": now}) + if err != nil { + c.jsonErr(500, 500, "删除激活码失败: "+err.Error()) + return + } + if n == 0 { + c.jsonErr(404, 404, "激活码不存在") + return + } + + c.ok(nil) +} + +type platformCursorActivationCodeGeneratePayload struct { + Count int `json:"count"` + Type int `json:"type"` + DurationDays int `json:"durationDays"` + OwnerUserID *uint64 `json:"ownerUserId"` + OwnerUserName *string `json:"ownerUserName"` + Remark *string `json:"remark"` +} + +func randomCursorActivationCode() (string, error) { + b := make([]byte, 12) + if _, err := rand.Read(b); err != nil { + return "", err + } + return "CUR-" + strings.ToUpper(hex.EncodeToString(b)), nil +} + +// Generate POST /platform/cursor/activationcode/generate +func (c *PlatformCursorActivationCodeController) Generate() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + body, _ := io.ReadAll(c.Ctx.Request.Body) + var p platformCursorActivationCodeGeneratePayload + if err := json.Unmarshal(body, &p); err != nil { + c.jsonErr(400, 400, "参数错误") + return + } + + if p.Count < 1 { + p.Count = 1 + } + if p.Count > 10000 { + c.jsonErr(400, 400, "单次最多生成 10000 个激活码") + return + } + if p.Type < 0 { + c.jsonErr(400, 400, "卡密类型不合法") + return + } + if p.DurationDays < 0 || p.DurationDays > 9999 { + c.jsonErr(400, 400, "有效天数范围为 0-9999") + return + } + if p.Type == 0 && p.DurationDays == 0 { + p.DurationDays = 30 + } + if p.Type > 0 && p.DurationDays == 0 { + p.DurationDays = p.Type + } + + createdIDs := make([]int64, 0, p.Count) + codes := make([]string, 0, p.Count) + now := time.Now() + + for len(createdIDs) < p.Count { + code, err := randomCursorActivationCode() + if err != nil { + c.jsonErr(500, 500, "生成激活码失败: "+err.Error()) + return + } + + row := models.PlatformCursorActivationCode{ + Code: code, + Type: p.Type, + Status: 0, + DurationDays: p.DurationDays, + OwnerUserID: p.OwnerUserID, + OwnerUserName: cursorActivationCodeTrimPtr(p.OwnerUserName), + Remark: cursorActivationCodeTrimPtr(p.Remark), + CreateTime: now, + } + if row.OwnerUserID != nil && *row.OwnerUserID == 0 { + row.OwnerUserID = nil + } + + id, err := models.Orm.Insert(&row) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), "duplicate") { + continue + } + c.jsonErr(500, 500, "生成激活码失败: "+err.Error()) + return + } + + createdIDs = append(createdIDs, id) + codes = append(codes, code) + } + + c.ok(map[string]interface{}{ + "count": len(createdIDs), + "ids": createdIDs, + "codes": codes, + }) +} + +// Enable POST /platform/cursor/activationcode/enable/:id +func (c *PlatformCursorActivationCodeController) Enable() { + c.changeStatus(0, "启用激活码失败") +} + +// Disable POST /platform/cursor/activationcode/disable/:id +func (c *PlatformCursorActivationCodeController) Disable() { + c.changeStatus(3, "禁用激活码失败") +} + +func (c *PlatformCursorActivationCodeController) changeStatus(status int8, failMsg string) { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) + if err != nil || id == 0 { + c.jsonErr(400, 400, "无效ID") + return + } + + now := time.Now() + n, err := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)). + Filter("id", id). + Filter("delete_time__isnull", true). + Update(map[string]interface{}{ + "status": status, + "update_time": now, + }) + if err != nil { + c.jsonErr(500, 500, failMsg+": "+err.Error()) + return + } + if n == 0 { + c.jsonErr(404, 404, "激活码不存在") + return + } + + c.ok(nil) +} + +// Export GET /platform/cursor/activationcode/export +func (c *PlatformCursorActivationCodeController) Export() { + if _, err := c.platformClaims(); err != nil { + c.jsonErr(401, 401, err.Error()) + return + } + + var rows []models.PlatformCursorActivationCode + _, err := c.filteredQuery().OrderBy("-id").Limit(50000).All(&rows) + if err != nil { + c.jsonErr(500, 500, "导出激活码失败: "+err.Error()) + return + } + + filename := fmt.Sprintf("cursor-activation-code-%s.csv", time.Now().Format("20060102150405")) + c.Ctx.Output.Header("Content-Type", "text/csv; charset=utf-8") + c.Ctx.Output.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) + + _, _ = c.Ctx.ResponseWriter.Write([]byte{0xEF, 0xBB, 0xBF}) + writer := csv.NewWriter(c.Ctx.ResponseWriter) + _ = writer.Write([]string{ + "ID", "激活码", "类型", "有效天数", "状态", "绑定账号", "绑定设备ID", "机器码", "归属用户ID", "归属用户", "激活时间", "过期时间", "创建时间", "备注", + }) + + statusText := map[int8]string{ + 0: "未使用", + 1: "已使用", + 2: "已过期", + 3: "已禁用", + } + + for i := range rows { + row := rows[i] + _ = writer.Write([]string{ + strconv.FormatUint(row.ID, 10), + row.Code, + cursorActivationCodeTypeName(row.Type), + strconv.Itoa(row.DurationDays), + statusText[row.Status], + stringPtrValue(row.BindAccount), + uint64PtrValue(row.BindDeviceID), + stringPtrValue(row.MachineCode), + uint64PtrValue(row.OwnerUserID), + stringPtrValue(row.OwnerUserName), + timePtrValue(row.ActivatedAt), + timePtrValue(row.ExpiredAt), + row.CreateTime.Format("2006-01-02 15:04:05"), + stringPtrValue(row.Remark), + }) + } + + writer.Flush() +} + +func stringPtrValue(value *string) string { + if value == nil { + return "" + } + return *value +} + +func uint64PtrValue(value *uint64) string { + if value == nil { + return "" + } + return strconv.FormatUint(*value, 10) +} + +func timePtrValue(value *time.Time) string { + if value == nil { + return "" + } + return value.Format("2006-01-02 15:04:05") +} diff --git a/docs/sql/yz_platform_cursor_activation_code.sql b/docs/sql/yz_platform_cursor_activation_code.sql new file mode 100644 index 0000000..d751da2 --- /dev/null +++ b/docs/sql/yz_platform_cursor_activation_code.sql @@ -0,0 +1,31 @@ +-- Cursor 激活码管理 +-- status: 0 未使用 1 已使用 2 已过期 3 已禁用 +-- type: 0 自定义 1 天卡 7 周卡 30 月卡 90 季卡 365 年卡 + +CREATE TABLE IF NOT EXISTS `yz_platform_cursor_activation_code` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `code` varchar(128) NOT NULL COMMENT '激活码', + `type` int NOT NULL DEFAULT 30 COMMENT '卡密类型:0自定义 1天卡 7周卡 30月卡 90季卡 365年卡', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态:0未使用 1已使用 2已过期 3已禁用', + `duration_days` int NOT NULL DEFAULT 30 COMMENT '有效天数', + `bind_account` varchar(128) DEFAULT NULL COMMENT '绑定账号', + `bind_device_id` bigint unsigned DEFAULT NULL COMMENT '绑定设备ID,关联 yz_platform_cursor_equipment.id', + `machine_code` varchar(128) DEFAULT NULL COMMENT '绑定设备机器码', + `device_info` varchar(1000) DEFAULT NULL COMMENT '绑定设备信息', + `owner_user_id` bigint unsigned DEFAULT NULL COMMENT '归属用户ID', + `owner_user_name` varchar(128) DEFAULT NULL COMMENT '归属用户名称', + `activated_at` datetime DEFAULT NULL COMMENT '激活时间', + `expired_at` datetime DEFAULT NULL COMMENT '过期时间', + `remark` varchar(1000) DEFAULT NULL COMMENT '备注', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `delete_time` datetime DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_code` (`code`), + KEY `idx_status_delete` (`status`,`delete_time`), + KEY `idx_type_status` (`type`,`status`), + KEY `idx_bind_account` (`bind_account`), + KEY `idx_bind_device_id` (`bind_device_id`), + KEY `idx_owner_user_id` (`owner_user_id`), + KEY `idx_expired_at` (`expired_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Cursor续杯激活码'; diff --git a/models/init.go b/models/init.go index 5ccb010..92a376a 100644 --- a/models/init.go +++ b/models/init.go @@ -57,6 +57,7 @@ func Init(_ string) { new(PlatformComplaint), new(SystemSoftwareUpgrade), new(PlatformCursorEquipment), + new(PlatformCursorActivationCode), new(PlatformAccountPoolKiro), new(PlatformAccountPoolWindsurf), new(PlatformAccountPoolCursor), diff --git a/models/platform_cursor_activation_code.go b/models/platform_cursor_activation_code.go new file mode 100644 index 0000000..26ed40f --- /dev/null +++ b/models/platform_cursor_activation_code.go @@ -0,0 +1,28 @@ +package models + +import "time" + +// PlatformCursorActivationCode Cursor 续杯激活码 yz_platform_cursor_activation_code +type PlatformCursorActivationCode struct { + ID uint64 `orm:"column(id);pk;auto" json:"id"` + Code string `orm:"column(code);size(128);unique" json:"code"` + Type int `orm:"column(type);default(30)" json:"type"` + Status int8 `orm:"column(status);default(0)" json:"status"` + DurationDays int `orm:"column(duration_days);default(30)" json:"durationDays"` + BindAccount *string `orm:"column(bind_account);size(128);null" json:"bindAccount"` + BindDeviceID *uint64 `orm:"column(bind_device_id);null" json:"bindDeviceId"` + MachineCode *string `orm:"column(machine_code);size(128);null" json:"machineCode"` + DeviceInfo *string `orm:"column(device_info);size(1000);null" json:"deviceInfo"` + OwnerUserID *uint64 `orm:"column(owner_user_id);null" json:"ownerUserId"` + OwnerUserName *string `orm:"column(owner_user_name);size(128);null" json:"ownerUserName"` + ActivatedAt *time.Time `orm:"column(activated_at);type(datetime);null" json:"activatedAt"` + ExpiredAt *time.Time `orm:"column(expired_at);type(datetime);null" json:"expiredAt"` + Remark *string `orm:"column(remark);size(1000);null" json:"remark"` + CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"createTime"` + UpdateTime *time.Time `orm:"column(update_time);auto_now;type(datetime);null" json:"updateTime"` + DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"deleteTime"` +} + +func (m *PlatformCursorActivationCode) TableName() string { + return "yz_platform_cursor_activation_code" +} diff --git a/routers/platform/platform.go b/routers/platform/platform.go index 65eb020..d036c98 100644 --- a/routers/platform/platform.go +++ b/routers/platform/platform.go @@ -172,6 +172,17 @@ func Register() { beego.Router("/platform/cursor/equipment/activationRecords", &controllers.PlatformCursorEquipmentController{}, "get:ActivationRecords") beego.Router("/platform/cursor/equipment/extractRecords", &controllers.PlatformCursorEquipmentController{}, "get:ExtractRecords") + // Cursor 激活码管理(yz_platform_cursor_activation_code) + beego.Router("/platform/cursor/activationcode/list", &controllers.PlatformCursorActivationCodeController{}, "get:List") + beego.Router("/platform/cursor/activationcode/detail/:id", &controllers.PlatformCursorActivationCodeController{}, "get:Detail") + beego.Router("/platform/cursor/activationcode/add", &controllers.PlatformCursorActivationCodeController{}, "post:Add") + beego.Router("/platform/cursor/activationcode/update", &controllers.PlatformCursorActivationCodeController{}, "post:Update") + beego.Router("/platform/cursor/activationcode/delete/:id", &controllers.PlatformCursorActivationCodeController{}, "post:Delete") + beego.Router("/platform/cursor/activationcode/generate", &controllers.PlatformCursorActivationCodeController{}, "post:Generate") + beego.Router("/platform/cursor/activationcode/enable/:id", &controllers.PlatformCursorActivationCodeController{}, "post:Enable") + beego.Router("/platform/cursor/activationcode/disable/:id", &controllers.PlatformCursorActivationCodeController{}, "post:Disable") + beego.Router("/platform/cursor/activationcode/export", &controllers.PlatformCursorActivationCodeController{}, "get:Export") + // 账号池管理(cursor/windsurf/krio) beego.Router("/platform/accountPool/cursor/list", &controllers.PlatformAccountPoolCursorController{}, "get:List") beego.Router("/platform/accountPool/cursor/add", &controllers.PlatformAccountPoolCursorController{}, "post:Add")