package controllers import ( "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" ) // PlatformCursorEquipmentController 平台端 Cursor 设备管理 type PlatformCursorEquipmentController struct { beego.Controller } func (c *PlatformCursorEquipmentController) 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 *PlatformCursorEquipmentController) 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 *PlatformCursorEquipmentController) ok(data interface{}) { c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data} _ = c.ServeJSON() } func cursorEquipmentTrimPtr(value *string) *string { if value == nil { return nil } v := strings.TrimSpace(*value) if v == "" { return nil } return &v } func cursorEquipmentTimePtr(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 cursorEquipmentStatusValid(status int8) bool { return status == 0 || status == 1 || status == 2 || status == 3 } func (c *PlatformCursorEquipmentController) cursorActivationSummary(row *models.PlatformCursorEquipment) (int64, *models.PlatformCursorActivationCode) { cond := orm.NewCondition(). And("delete_time__isnull", true). AndCond(orm.NewCondition(). Or("bind_device_id", row.ID). Or("machine_code", row.MachineCode)) qs := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).SetCond(cond) count, _ := qs.Count() var latest models.PlatformCursorActivationCode if err := qs.OrderBy("-activated_at", "-id").One(&latest); err != nil { return count, nil } return count, &latest } func (c *PlatformCursorEquipmentController) cursorExtractSummary() (int64, *models.PlatformAccountPoolCursor) { qs := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)). Filter("delete_time__isnull", true). Filter("is_extracted__gt", 0) count, _ := qs.Count() var latest models.PlatformAccountPoolCursor if err := qs.OrderBy("-extracted_time", "-id").One(&latest); err != nil { return count, nil } return count, &latest } func (c *PlatformCursorEquipmentController) rowToMap(row *models.PlatformCursorEquipment) map[string]interface{} { activationCount, latestActivation := c.cursorActivationSummary(row) extractCount, latestExtract := c.cursorExtractSummary() var bindActivationCode interface{} var activationCodeId interface{} var lastActivatedAt interface{} = row.ActivationTime var expireTime interface{} = row.ExpireTime var lastExtractedAt interface{} if latestActivation != nil { bindActivationCode = latestActivation.Code activationCodeId = latestActivation.ID if latestActivation.ActivatedAt != nil { lastActivatedAt = latestActivation.ActivatedAt } if latestActivation.ExpiredAt != nil { expireTime = latestActivation.ExpiredAt } } if latestExtract != nil { lastExtractedAt = latestExtract.ExtractedTime } return map[string]interface{}{ "id": row.ID, "deviceInfo": row.DeviceInfo, "machineCode": row.MachineCode, "status": row.Status, "system": row.System, "os": row.System, "version": row.Version, "bindAccount": row.BindAccount, "bindActivationCode": bindActivationCode, "activationCode": bindActivationCode, "activationCodeId": activationCodeId, "ownerUserId": row.OwnerUserID, "ownerUserName": row.OwnerUserName, "activationTime": lastActivatedAt, "lastActivatedAt": lastActivatedAt, "expireTime": expireTime, "expiredAt": expireTime, "activationCount": activationCount, "extractCount": extractCount, "lastExtractedAt": lastExtractedAt, "remark": row.Remark, "createTime": row.CreateTime, "updateTime": row.UpdateTime, } } // List GET /platform/cursor/equipment/list func (c *PlatformCursorEquipmentController) 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 } keyword := strings.TrimSpace(c.GetString("keyword")) statusText := strings.TrimSpace(c.GetString("status")) system := strings.TrimSpace(c.GetString("system")) if system == "" { system = strings.TrimSpace(c.GetString("os")) } qs := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).Filter("delete_time__isnull", true) if keyword != "" { cond := orm.NewCondition(). Or("machine_code__icontains", keyword). Or("device_info__icontains", keyword). Or("bind_account__icontains", keyword). Or("owner_user_name__icontains", keyword). Or("remark__icontains", keyword) qs = qs.SetCond(cond) } if statusText != "" { status, err := strconv.ParseInt(statusText, 10, 8) if err == nil && cursorEquipmentStatusValid(int8(status)) { qs = qs.Filter("status", int8(status)) } } if system != "" { qs = qs.Filter("system__icontains", system) } total, _ := qs.Count() var rows []models.PlatformCursorEquipment _, 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/equipment/detail/:id func (c *PlatformCursorEquipmentController) 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.PlatformCursorEquipment err = models.Orm.QueryTable(new(models.PlatformCursorEquipment)). Filter("id", id). Filter("delete_time__isnull", true). One(&row) if err != nil { c.jsonErr(404, 404, "设备不存在") return } c.ok(c.rowToMap(&row)) } type platformCursorEquipmentPayload struct { ID *uint64 `json:"id"` DeviceInfo *string `json:"deviceInfo"` MachineCode *string `json:"machineCode"` Status *int8 `json:"status"` System *string `json:"system"` Version *string `json:"version"` BindAccount *string `json:"bindAccount"` OwnerUserID *uint64 `json:"ownerUserId"` OwnerUserName *string `json:"ownerUserName"` ActivationTime *string `json:"activationTime"` ExpireTime *string `json:"expireTime"` Remark *string `json:"remark"` } func (c *PlatformCursorEquipmentController) readPayload() (*platformCursorEquipmentPayload, error) { body, _ := io.ReadAll(c.Ctx.Request.Body) var p platformCursorEquipmentPayload if err := json.Unmarshal(body, &p); err != nil { return nil, err } return &p, nil } func (c *PlatformCursorEquipmentController) payloadToUpdateMap(p *platformCursorEquipmentPayload, includeMachineCode bool) (map[string]interface{}, error) { up := map[string]interface{}{} if includeMachineCode { if p.MachineCode == nil || strings.TrimSpace(*p.MachineCode) == "" { return nil, fmt.Errorf("机器码不能为空") } up["machine_code"] = strings.TrimSpace(*p.MachineCode) } else if p.MachineCode != nil { if strings.TrimSpace(*p.MachineCode) == "" { return nil, fmt.Errorf("机器码不能为空") } up["machine_code"] = strings.TrimSpace(*p.MachineCode) } if p.DeviceInfo != nil { up["device_info"] = cursorEquipmentTrimPtr(p.DeviceInfo) } if p.Status != nil { if !cursorEquipmentStatusValid(*p.Status) { return nil, fmt.Errorf("状态不合法,支持:0 未激活、1 激活中、2 已过期、3 已禁用") } up["status"] = *p.Status } if p.System != nil { up["system"] = cursorEquipmentTrimPtr(p.System) } if p.Version != nil { up["version"] = cursorEquipmentTrimPtr(p.Version) } if p.BindAccount != nil { up["bind_account"] = cursorEquipmentTrimPtr(p.BindAccount) } 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"] = cursorEquipmentTrimPtr(p.OwnerUserName) } if p.ActivationTime != nil { up["activation_time"] = cursorEquipmentTimePtr(p.ActivationTime) } if p.ExpireTime != nil { up["expire_time"] = cursorEquipmentTimePtr(p.ExpireTime) } if p.Remark != nil { up["remark"] = cursorEquipmentTrimPtr(p.Remark) } return up, nil } // Add POST /platform/cursor/equipment/add func (c *PlatformCursorEquipmentController) 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 } status := int8(0) if value, ok := up["status"]; ok { status = value.(int8) } row := models.PlatformCursorEquipment{ MachineCode: up["machine_code"].(string), Status: status, DeviceInfo: cursorEquipmentTrimPtr(p.DeviceInfo), System: cursorEquipmentTrimPtr(p.System), Version: cursorEquipmentTrimPtr(p.Version), BindAccount: cursorEquipmentTrimPtr(p.BindAccount), OwnerUserID: p.OwnerUserID, OwnerUserName: cursorEquipmentTrimPtr(p.OwnerUserName), ActivationTime: cursorEquipmentTimePtr(p.ActivationTime), ExpireTime: cursorEquipmentTimePtr(p.ExpireTime), Remark: cursorEquipmentTrimPtr(p.Remark), CreateTime: time.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") { c.jsonErr(400, 400, "机器码已存在") return } c.jsonErr(500, 500, "新增设备失败: "+err.Error()) return } c.ok(map[string]interface{}{"id": id}) } // Update POST /platform/cursor/equipment/update func (c *PlatformCursorEquipmentController) 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.PlatformCursorEquipment)). 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/equipment/delete/:id func (c *PlatformCursorEquipmentController) 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.PlatformCursorEquipment)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now}) if err != nil { c.jsonErr(500, 500, "删除设备失败: "+err.Error()) return } if n == 0 { c.jsonErr(404, 404, "设备不存在") return } c.ok(nil) } type platformCursorEquipmentActivatePayload struct { ID uint64 `json:"id"` } // Activate POST /platform/cursor/equipment/activate func (c *PlatformCursorEquipmentController) Activate() { if _, err := c.platformClaims(); err != nil { c.jsonErr(401, 401, err.Error()) return } body, _ := io.ReadAll(c.Ctx.Request.Body) var p platformCursorEquipmentActivatePayload if err := json.Unmarshal(body, &p); err != nil || p.ID == 0 { c.jsonErr(400, 400, "无效ID") return } now := time.Now() n, err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)). Filter("id", p.ID). Filter("delete_time__isnull", true). Update(map[string]interface{}{ "status": int8(1), "activation_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) } // ActivationRecords GET /platform/cursor/equipment/activationRecords func (c *PlatformCursorEquipmentController) ActivationRecords() { if _, err := c.platformClaims(); err != nil { c.jsonErr(401, 401, err.Error()) return } equipmentID, _ := c.GetUint64("equipmentId") if equipmentID == 0 { equipmentID, _ = c.GetUint64("id") } if equipmentID == 0 { c.jsonErr(400, 400, "缺少设备ID") return } var equipment models.PlatformCursorEquipment if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)). Filter("id", equipmentID). Filter("delete_time__isnull", true). One(&equipment); err != nil { c.jsonErr(404, 404, "设备不存在") 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 } cond := orm.NewCondition(). And("delete_time__isnull", true). AndCond(orm.NewCondition(). Or("bind_device_id", equipment.ID). Or("machine_code", equipment.MachineCode)) qs := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).SetCond(cond) total, _ := qs.Count() var rows []models.PlatformCursorActivationCode if _, err := qs.OrderBy("-activated_at", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil { c.jsonErr(500, 500, "获取激活记录失败: "+err.Error()) return } list := make([]map[string]interface{}, 0, len(rows)) for i := range rows { row := rows[i] list = append(list, map[string]interface{}{ "id": row.ID, "code": row.Code, "activationCode": row.Code, "status": row.Status, "durationDays": row.DurationDays, "machineCode": row.MachineCode, "deviceInfo": row.DeviceInfo, "ownerUserId": row.OwnerUserID, "ownerUserName": row.OwnerUserName, "activatedAt": row.ActivatedAt, "expiredAt": row.ExpiredAt, "createdAt": row.CreateTime, "remark": row.Remark, }) } c.ok(map[string]interface{}{ "list": list, "total": total, "page": page, "pageSize": pageSize, }) } // ExtractRecords GET /platform/cursor/equipment/extractRecords func (c *PlatformCursorEquipmentController) ExtractRecords() { if _, err := c.platformClaims(); err != nil { c.jsonErr(401, 401, err.Error()) return } equipmentID, _ := c.GetUint64("equipmentId") if equipmentID == 0 { equipmentID, _ = c.GetUint64("id") } if equipmentID == 0 { c.jsonErr(400, 400, "缺少设备ID") return } var equipment models.PlatformCursorEquipment if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)). Filter("id", equipmentID). Filter("delete_time__isnull", true). One(&equipment); err != nil { c.jsonErr(404, 404, "设备不存在") 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 := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)). Filter("delete_time__isnull", true). Filter("is_extracted__gt", 0) total, _ := qs.Count() var rows []models.PlatformAccountPoolCursor if _, err := qs.OrderBy("-extracted_time", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil { c.jsonErr(500, 500, "获取提取记录失败: "+err.Error()) return } list := make([]map[string]interface{}, 0, len(rows)) for i := range rows { row := rows[i] content := buildCardResult(&row.Account, &row.Password, row.Token, row.DataType) list = append(list, map[string]interface{}{ "id": row.ID, "status": row.IsExtracted, "isExtracted": row.IsExtracted, "platform": row.ExtractedPlatform, "extractedPlatform": row.ExtractedPlatform, "dataType": row.DataType, "type": row.DataType, "account": row.Account, "password": row.Password, "token": row.Token, "content": content, "extractedAt": row.ExtractedTime, "createdAt": row.ExtractedTime, "remark": row.Remark, }) } c.ok(map[string]interface{}{ "list": list, "total": total, "page": page, "pageSize": pageSize, }) }