diff --git a/go/controllers/api_cursor_equipment.go b/go/controllers/api_cursor_equipment.go index d0e00e7..6dc9887 100644 --- a/go/controllers/api_cursor_equipment.go +++ b/go/controllers/api_cursor_equipment.go @@ -126,9 +126,68 @@ func (c *ApiCursorEquipmentController) jsonResult(code int, msg string, data int // 兼容 snake_case 字段,例如 machine_code、device_info、bind_account。 func (c *ApiCursorEquipmentController) Report() { var p cursorEquipmentReportPayload - if err := json.Unmarshal(c.Ctx.Input.RequestBody, &p); err != nil { - c.jsonResult(400, "参数错误", nil) - return + body := c.Ctx.Input.RequestBody + if len(body) > 0 { + if err := json.Unmarshal(body, &p); err != nil { + c.jsonResult(400, "参数错误", nil) + return + } + } + // 兼容 query string 参数 + if p.MachineCode == "" { + p.MachineCode = c.GetString("machineCode") + } + if p.MachineCodeSnake == "" { + p.MachineCodeSnake = c.GetString("machine_code") + } + if p.DeviceInfo == "" { + p.DeviceInfo = c.GetString("deviceInfo") + } + if p.DeviceInfoSnake == "" { + p.DeviceInfoSnake = c.GetString("device_info") + } + if p.System == "" { + p.System = c.GetString("system") + } + if p.Version == "" { + p.Version = c.GetString("version") + } + if p.BindAccount == "" { + p.BindAccount = c.GetString("bindAccount") + } + if p.BindAccountSnake == "" { + p.BindAccountSnake = c.GetString("bind_account") + } + if p.OwnerUserName == "" { + p.OwnerUserName = c.GetString("ownerUserName") + } + if p.OwnerUserNameSnake == "" { + p.OwnerUserNameSnake = c.GetString("owner_user_name") + } + if p.ActivationTime == "" { + p.ActivationTime = c.GetString("activationTime") + } + if p.ActivationTimeSnake == "" { + p.ActivationTimeSnake = c.GetString("activation_time") + } + if p.ExpireTime == "" { + p.ExpireTime = c.GetString("expireTime") + } + if p.ExpireTimeSnake == "" { + p.ExpireTimeSnake = c.GetString("expire_time") + } + if p.Remark == "" { + p.Remark = c.GetString("remark") + } + if p.Status == nil { + if s, err := c.GetInt8("status"); err == nil { + p.Status = &s + } + } + if p.OwnerUserID == nil { + if uid, err := c.GetUint64("ownerUserId"); err == nil && uid > 0 { + p.OwnerUserID = &uid + } } machineCode := cursorFirstNonEmpty(p.MachineCode, p.MachineCodeSnake) @@ -234,11 +293,35 @@ func (c *ApiCursorEquipmentController) Report() { row.UpdateTime = &now } + // 查询该设备最新激活码,补全激活时间和到期时间 + var retActivationTime interface{} = row.ActivationTime + var retExpireTime interface{} = row.ExpireTime + + var latestCode models.PlatformCursorActivationCode + cond := orm.NewCondition(). + And("delete_time__isnull", true). + AndCond(orm.NewCondition(). + Or("bind_device_id", row.ID). + Or("machine_code", row.MachineCode)) + if err := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)). + SetCond(cond). + OrderBy("-activated_at", "-id"). + One(&latestCode); err == nil { + if latestCode.ActivatedAt != nil { + retActivationTime = latestCode.ActivatedAt + } + if latestCode.ExpiredAt != nil { + retExpireTime = latestCode.ExpiredAt + } + } + c.jsonResult(200, "success", map[string]interface{}{ - "id": row.ID, - "machineCode": row.MachineCode, - "status": row.Status, - "created": created, + "id": row.ID, + "machineCode": row.MachineCode, + "status": row.Status, + "created": created, + "activationTime": retActivationTime, + "expireTime": retExpireTime, }) } diff --git a/go/controllers/api_getcard.go b/go/controllers/api_getcard.go index 06a6cae..0c8b725 100644 --- a/go/controllers/api_getcard.go +++ b/go/controllers/api_getcard.go @@ -23,6 +23,7 @@ var validPlatformTypes = map[string]bool{ "jingdong": true, "douyin": true, "local": true, + "xubei": true, } // validModules 支持的号池模块 @@ -48,7 +49,7 @@ func (c *ApiGetCardController) cardOK(text string) { // GET /api/getcard?type=xianyu&module=cursor&data_type=tk // // 参数: -// - type (必填) 来源平台:xianyu / taobao / pinduoduo / jingdong / local +// - type (必填) 来源平台:xianyu / taobao / pinduoduo / jingdong / local / xubei // - module (必填) 号池模块:cursor / windsurf / krio // - data_type (可选) 账号类型:account / tk / account_tk,不传则取任意未提取的 func (c *ApiGetCardController) GetCard() { @@ -62,7 +63,7 @@ func (c *ApiGetCardController) GetCard() { return } if !validPlatformTypes[platform] { - c.cardErr(400, 400, fmt.Sprintf("不支持的平台类型: %s,支持: xianyu/taobao/pinduoduo/jingdong/local", platform)) + c.cardErr(400, 400, fmt.Sprintf("不支持的平台类型: %s,支持: xianyu/taobao/pinduoduo/jingdong/local/xubei", platform)) return } if module == "" { diff --git a/go/controllers/platform_account_pool.go b/go/controllers/platform_account_pool.go index 264511b..08a2762 100644 --- a/go/controllers/platform_account_pool.go +++ b/go/controllers/platform_account_pool.go @@ -463,7 +463,7 @@ func extractPoolRow(c *beego.Controller, module string) { var payload struct { ID uint64 `json:"id"` Type string `json:"type"` - Platform string `json:"platform"` // local | xianyu | taobao | pinduoduo | jingdong | douyin | ziyoushangcheng + Platform string `json:"platform"` // local | xianyu | taobao | pinduoduo | jingdong | douyin | ziyoushangcheng | xubei Remark string `json:"remark"` Replenish bool `json:"replenish"` // true 时写入 is_extracted=2(补号),否则为 1(已提取) } @@ -471,13 +471,7 @@ func extractPoolRow(c *beego.Controller, module string) { poolJSONErr(c, 400, 400, "参数错误") return } - if payload.Platform != "local" && - payload.Platform != "xianyu" && - payload.Platform != "taobao" && - payload.Platform != "pinduoduo" && - payload.Platform != "jingdong" && - payload.Platform != "douyin" && - payload.Platform != "ziyoushangcheng" { + if !validExtractPlatform(payload.Platform) { poolJSONErr(c, 400, 400, "提取平台错误") return } @@ -609,7 +603,7 @@ func replenishPoolRow(c *beego.Controller, module string) { poolJSONErr(c, 400, 400, "账号类型不正确") return } - validPlatforms := map[string]bool{"local": true, "xianyu": true, "pinduoduo": true, "jingdong": true, "douyin": true} + validPlatforms := map[string]bool{"local": true, "xianyu": true, "pinduoduo": true, "jingdong": true, "douyin": true, "xubei": true} if !validPlatforms[payload.Platform] { poolJSONErr(c, 400, 400, "提取平台错误") return @@ -817,7 +811,7 @@ func updatePoolRemark(c *beego.Controller, module string) { func validExtractPlatform(platform string) bool { switch platform { - case "local", "xianyu", "taobao", "pinduoduo", "jingdong", "douyin", "ziyoushangcheng": + case "local", "xianyu", "taobao", "pinduoduo", "jingdong", "douyin", "ziyoushangcheng", "xubei": return true default: return false diff --git a/platform/src/views/accountpool/cursor/components/detail.vue b/platform/src/views/accountpool/cursor/components/detail.vue index 21505ac..12b22fa 100644 --- a/platform/src/views/accountpool/cursor/components/detail.vue +++ b/platform/src/views/accountpool/cursor/components/detail.vue @@ -41,6 +41,7 @@ const PLATFORM_MAP = { jingdong: { label: "京东", type: "primary" }, douyin: { label: "抖音", type: "success" }, ziyoushangcheng: { label: "自有商城", type: "warning" }, + xubei: { label: "续杯", type: "primary" }, }; const statusInfo = computed(() => { diff --git a/platform/src/views/accountpool/cursor/index.vue b/platform/src/views/accountpool/cursor/index.vue index 3d5d57b..e79edbe 100644 --- a/platform/src/views/accountpool/cursor/index.vue +++ b/platform/src/views/accountpool/cursor/index.vue @@ -439,6 +439,7 @@ const PLATFORM_MAP = { pinduoduo: { label: '拼多多', type: 'danger' }, jingdong: { label: '京东', type: 'primary' }, douyin: { label: '抖音', type: 'success' }, + xubei: { label: '续杯', type: 'primary' }, }; function platformText(platform) { @@ -648,7 +649,7 @@ onUnmounted(() => { const BASE_URL = "https://api.yunzer.cn"; const paramDocs = [ - { name: 'type', required: true, desc: '来源平台,用于标记本次提取来自哪个渠道', values: 'xianyu / taobao / pinduoduo / jingdong / local' }, + { name: 'type', required: true, desc: '来源平台,用于标记本次提取来自哪个渠道', values: 'xianyu / taobao / pinduoduo / jingdong / local / xubei' }, { name: 'module', required: true, desc: '号池模块,指定从哪个产品的号池提取', values: 'cursor / windsurf / krio' }, { name: 'data_type', required: false, desc: '账号类型,不传则提取任意类型', values: 'account / tk / account_tk' }, ]; @@ -659,6 +660,7 @@ const platformDocs = [ { value: 'jingdong', label: '京东', desc: '京东平台发货调用' }, { value: 'douyin', label: '抖音', desc: '抖音平台发货调用' }, { value: 'local', label: '本地', desc: '本地手动调用' }, + { value: 'xubei', label: '续杯', desc: '续杯渠道调用' }, ]; const moduleDocs = [