diff --git a/controllers/platform_account_pool.go b/controllers/platform_account_pool.go new file mode 100644 index 0000000..32e32a5 --- /dev/null +++ b/controllers/platform_account_pool.go @@ -0,0 +1,438 @@ +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" +) + +type PlatformAccountPoolCursorController struct{ beego.Controller } +type PlatformAccountPoolWindsurfController struct{ beego.Controller } +type PlatformAccountPoolKrioController struct{ beego.Controller } + +type accountPoolCreateRow struct { + DataType string `json:"type"` + Account string `json:"account"` + Password string `json:"password"` + Token string `json:"token"` + Remark string `json:"remark"` +} + +func requirePlatformAuth(c *beego.Controller) (*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 poolJSONErr(c *beego.Controller, httpStatus, code int, msg string) { + c.Ctx.Output.SetStatus(httpStatus) + c.Data["json"] = map[string]interface{}{"code": code, "msg": msg} + _ = c.ServeJSON() +} + +func isValidPoolType(t string) bool { + return t == "account" || t == "tk" || t == "account_tk" +} + +func validateCreateRow(row accountPoolCreateRow) error { + if !isValidPoolType(row.DataType) { + return fmt.Errorf("账号类型不正确") + } + row.Account = strings.TrimSpace(row.Account) + row.Password = strings.TrimSpace(row.Password) + row.Token = strings.TrimSpace(row.Token) + if row.DataType == "account" && (row.Account == "" || row.Password == "") { + return fmt.Errorf("账号密码类型必须填写账号和密码") + } + if row.DataType == "tk" && row.Token == "" { + return fmt.Errorf("token类型必须填写token") + } + if row.DataType == "account_tk" && (row.Account == "" || row.Password == "" || row.Token == "") { + return fmt.Errorf("账号密码+token类型必须填写账号、密码、token") + } + return nil +} + +func listPoolRows(c *beego.Controller, module string) { + if _, err := requirePlatformAuth(c); err != nil { + poolJSONErr(c, 401, 401, err.Error()) + return + } + page, _ := c.GetInt("page", 1) + pageSize, _ := c.GetInt("pageSize", 30) + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 30 + } + if pageSize > 200 { + pageSize = 200 + } + keyword := strings.TrimSpace(c.GetString("keyword")) + dataType := strings.TrimSpace(c.GetString("type")) + status := strings.TrimSpace(c.GetString("status")) + + var table string + switch module { + case "cursor": + table = new(models.PlatformAccountPoolCursor).TableName() + case "windsurf": + table = new(models.PlatformAccountPoolWindsurf).TableName() + case "krio": + table = new(models.PlatformAccountPoolKiro).TableName() + default: + poolJSONErr(c, 400, 400, "无效模块") + return + } + + qs := models.Orm.QueryTable(table) + if dataType != "" && isValidPoolType(dataType) { + qs = qs.Filter("data_type", dataType) + } + if status == "unused" { + qs = qs.Filter("is_extracted", 0) + } + if status == "extracted" { + qs = qs.Filter("is_extracted", 1) + } + if keyword != "" { + qs = qs.Filter("account__icontains", keyword).Filter("remark__icontains", keyword) + } + total, err := qs.Count() + if err != nil { + poolJSONErr(c, 500, 500, "获取列表失败: "+err.Error()) + return + } + + var rows []orm.Params + _, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).Values(&rows) + if err != nil { + poolJSONErr(c, 500, 500, "获取列表失败: "+err.Error()) + return + } + + c.Data["json"] = map[string]interface{}{ + "code": 200, + "msg": "success", + "data": map[string]interface{}{ + "list": rows, + "total": total, + }, + } + _ = c.ServeJSON() +} + +func addPoolRow(c *beego.Controller, module string) { + if _, err := requirePlatformAuth(c); err != nil { + poolJSONErr(c, 401, 401, err.Error()) + return + } + raw, err := io.ReadAll(c.Ctx.Request.Body) + if err != nil { + poolJSONErr(c, 400, 400, "参数错误") + return + } + var row accountPoolCreateRow + if err := json.Unmarshal(raw, &row); err != nil { + poolJSONErr(c, 400, 400, "参数错误") + return + } + if err := validateCreateRow(row); err != nil { + poolJSONErr(c, 400, 400, err.Error()) + return + } + + switch module { + case "cursor": + r := &models.PlatformAccountPoolCursor{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + } + _, err = models.Orm.Insert(r) + case "windsurf": + r := &models.PlatformAccountPoolWindsurf{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + } + _, err = models.Orm.Insert(r) + case "krio": + r := &models.PlatformAccountPoolKiro{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + } + _, err = models.Orm.Insert(r) + default: + poolJSONErr(c, 400, 400, "无效模块") + return + } + if err != nil { + poolJSONErr(c, 500, 500, "添加失败: "+err.Error()) + return + } + + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "添加成功"} + _ = c.ServeJSON() +} + +func batchAddPoolRows(c *beego.Controller, module string) { + if _, err := requirePlatformAuth(c); err != nil { + poolJSONErr(c, 401, 401, err.Error()) + return + } + raw, err := io.ReadAll(c.Ctx.Request.Body) + if err != nil { + poolJSONErr(c, 400, 400, "参数错误") + return + } + var payload struct { + Rows []accountPoolCreateRow `json:"rows"` + } + if err := json.Unmarshal(raw, &payload); err != nil || len(payload.Rows) == 0 { + poolJSONErr(c, 400, 400, "参数错误") + return + } + for _, row := range payload.Rows { + if err := validateCreateRow(row); err != nil { + poolJSONErr(c, 400, 400, err.Error()) + return + } + } + for _, row := range payload.Rows { + switch module { + case "cursor": + _, err = models.Orm.Insert(&models.PlatformAccountPoolCursor{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + }) + case "windsurf": + _, err = models.Orm.Insert(&models.PlatformAccountPoolWindsurf{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + }) + case "krio": + _, err = models.Orm.Insert(&models.PlatformAccountPoolKiro{ + DataType: strings.TrimSpace(row.DataType), + Account: strings.TrimSpace(row.Account), + Password: strings.TrimSpace(row.Password), + Token: strings.TrimSpace(row.Token), + Remark: strings.TrimSpace(row.Remark), + IsExtracted: 0, + }) + default: + poolJSONErr(c, 400, 400, "无效模块") + return + } + if err != nil { + poolJSONErr(c, 500, 500, "批量添加失败: "+err.Error()) + return + } + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "批量添加成功"} + _ = c.ServeJSON() +} + +func getPoolDetail(c *beego.Controller, module string) { + if _, err := requirePlatformAuth(c); err != nil { + poolJSONErr(c, 401, 401, err.Error()) + return + } + id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64) + if err != nil || id == 0 { + poolJSONErr(c, 400, 400, "无效ID") + return + } + + switch module { + case "cursor": + var row models.PlatformAccountPoolCursor + if err := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).Filter("id", id).One(&row); err != nil { + poolJSONErr(c, 404, 404, "记录不存在") + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": row} + case "windsurf": + var row models.PlatformAccountPoolWindsurf + if err := models.Orm.QueryTable(new(models.PlatformAccountPoolWindsurf)).Filter("id", id).One(&row); err != nil { + poolJSONErr(c, 404, 404, "记录不存在") + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": row} + case "krio": + var row models.PlatformAccountPoolKiro + if err := models.Orm.QueryTable(new(models.PlatformAccountPoolKiro)).Filter("id", id).One(&row); err != nil { + poolJSONErr(c, 404, 404, "记录不存在") + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": row} + default: + poolJSONErr(c, 400, 400, "无效模块") + return + } + _ = c.ServeJSON() +} + +func extractPoolRow(c *beego.Controller, module string) { + if _, err := requirePlatformAuth(c); err != nil { + poolJSONErr(c, 401, 401, err.Error()) + return + } + raw, err := io.ReadAll(c.Ctx.Request.Body) + if err != nil { + poolJSONErr(c, 400, 400, "参数错误") + return + } + var payload struct { + ID uint64 `json:"id"` + Type string `json:"type"` + Platform string `json:"platform"` // local | xianyu + } + if err := json.Unmarshal(raw, &payload); err != nil { + poolJSONErr(c, 400, 400, "参数错误") + return + } + if payload.Platform != "local" && payload.Platform != "xianyu" { + poolJSONErr(c, 400, 400, "提取平台错误") + return + } + if payload.Type != "" && !isValidPoolType(payload.Type) { + poolJSONErr(c, 400, 400, "提取类型错误") + return + } + + now := time.Now() + platform := payload.Platform + + switch module { + case "cursor": + var row models.PlatformAccountPoolCursor + qs := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).Filter("is_extracted", 0) + if payload.ID > 0 { + qs = qs.Filter("id", payload.ID) + } else if payload.Type != "" { + qs = qs.Filter("data_type", payload.Type) + } + if err := qs.OrderBy("id").One(&row); err != nil { + poolJSONErr(c, 404, 404, "没有可提取数据") + return + } + _, err = models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).Filter("id", row.ID).Update(map[string]interface{}{ + "is_extracted": 1, + "extracted_time": now, + "extracted_platform": platform, + }) + if err != nil { + poolJSONErr(c, 500, 500, "提取失败: "+err.Error()) + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "提取成功", "data": row} + case "windsurf": + var row models.PlatformAccountPoolWindsurf + qs := models.Orm.QueryTable(new(models.PlatformAccountPoolWindsurf)).Filter("is_extracted", 0) + if payload.ID > 0 { + qs = qs.Filter("id", payload.ID) + } else if payload.Type != "" { + qs = qs.Filter("data_type", payload.Type) + } + if err := qs.OrderBy("id").One(&row); err != nil { + poolJSONErr(c, 404, 404, "没有可提取数据") + return + } + _, err = models.Orm.QueryTable(new(models.PlatformAccountPoolWindsurf)).Filter("id", row.ID).Update(map[string]interface{}{ + "is_extracted": 1, + "extracted_time": now, + "extracted_platform": platform, + }) + if err != nil { + poolJSONErr(c, 500, 500, "提取失败: "+err.Error()) + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "提取成功", "data": row} + case "krio": + var row models.PlatformAccountPoolKiro + qs := models.Orm.QueryTable(new(models.PlatformAccountPoolKiro)).Filter("is_extracted", 0) + if payload.ID > 0 { + qs = qs.Filter("id", payload.ID) + } else if payload.Type != "" { + qs = qs.Filter("data_type", payload.Type) + } + if err := qs.OrderBy("id").One(&row); err != nil { + poolJSONErr(c, 404, 404, "没有可提取数据") + return + } + _, err = models.Orm.QueryTable(new(models.PlatformAccountPoolKiro)).Filter("id", row.ID).Update(map[string]interface{}{ + "is_extracted": 1, + "extracted_time": now, + "extracted_platform": platform, + }) + if err != nil { + poolJSONErr(c, 500, 500, "提取失败: "+err.Error()) + return + } + c.Data["json"] = map[string]interface{}{"code": 200, "msg": "提取成功", "data": row} + default: + poolJSONErr(c, 400, 400, "无效模块") + return + } + _ = c.ServeJSON() +} + +func (c *PlatformAccountPoolCursorController) List() { listPoolRows(&c.Controller, "cursor") } +func (c *PlatformAccountPoolCursorController) Add() { addPoolRow(&c.Controller, "cursor") } +func (c *PlatformAccountPoolCursorController) BatchAdd() { batchAddPoolRows(&c.Controller, "cursor") } +func (c *PlatformAccountPoolCursorController) Detail() { getPoolDetail(&c.Controller, "cursor") } +func (c *PlatformAccountPoolCursorController) Extract() { extractPoolRow(&c.Controller, "cursor") } + +func (c *PlatformAccountPoolWindsurfController) List() { listPoolRows(&c.Controller, "windsurf") } +func (c *PlatformAccountPoolWindsurfController) Add() { addPoolRow(&c.Controller, "windsurf") } +func (c *PlatformAccountPoolWindsurfController) BatchAdd() { batchAddPoolRows(&c.Controller, "windsurf") } +func (c *PlatformAccountPoolWindsurfController) Detail() { getPoolDetail(&c.Controller, "windsurf") } +func (c *PlatformAccountPoolWindsurfController) Extract() { extractPoolRow(&c.Controller, "windsurf") } + +func (c *PlatformAccountPoolKrioController) List() { listPoolRows(&c.Controller, "krio") } +func (c *PlatformAccountPoolKrioController) Add() { addPoolRow(&c.Controller, "krio") } +func (c *PlatformAccountPoolKrioController) BatchAdd() { batchAddPoolRows(&c.Controller, "krio") } +func (c *PlatformAccountPoolKrioController) Detail() { getPoolDetail(&c.Controller, "krio") } +func (c *PlatformAccountPoolKrioController) Extract() { extractPoolRow(&c.Controller, "krio") } diff --git a/models/init.go b/models/init.go index ec7ad0f..fe99dfc 100644 --- a/models/init.go +++ b/models/init.go @@ -53,6 +53,9 @@ func Init(_ string) { new(ComplaintCategory), new(PlatformComplaint), new(SystemSoftwareUpgrade), + new(PlatformAccountPoolKiro), + new(PlatformAccountPoolWindsurf), + new(PlatformAccountPoolCursor), ) // 创建全局 Ormer diff --git a/models/platform_account_pool.go b/models/platform_account_pool.go new file mode 100644 index 0000000..9c5cdaf --- /dev/null +++ b/models/platform_account_pool.go @@ -0,0 +1,63 @@ +package models + +import "time" + +// PlatformAccountPoolKiro 号池表: yz_platform_account_pool_krio +type PlatformAccountPoolKiro struct { + ID uint64 `orm:"column(id);pk;auto" json:"id"` + DataType string `orm:"column(data_type);size(32)" json:"data_type"` // account | tk | account_tk + Account string `orm:"column(account);size(128);default()" json:"account"` + Password string `orm:"column(password);size(255);default()" json:"password"` + Token string `orm:"column(token);type(text);null" json:"token"` + Remark string `orm:"column(remark);size(255);default()" json:"remark"` + IsExtracted int8 `orm:"column(is_extracted);default(0)" json:"is_extracted"` + ExtractedTime *time.Time `orm:"column(extracted_time);type(datetime);null" json:"extracted_time"` + ExtractedPlatform *string `orm:"column(extracted_platform);size(32);null" json:"extracted_platform"` + CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"` + UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"` + DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"` +} + +func (m *PlatformAccountPoolKiro) TableName() string { + return "yz_platform_account_pool_krio" +} + +// PlatformAccountPoolWindsurf 号池表: yz_platform_account_pool_windsurf +type PlatformAccountPoolWindsurf struct { + ID uint64 `orm:"column(id);pk;auto" json:"id"` + DataType string `orm:"column(data_type);size(32)" json:"data_type"` // account | tk | account_tk + Account string `orm:"column(account);size(128);default()" json:"account"` + Password string `orm:"column(password);size(255);default()" json:"password"` + Token string `orm:"column(token);type(text);null" json:"token"` + Remark string `orm:"column(remark);size(255);default()" json:"remark"` + IsExtracted int8 `orm:"column(is_extracted);default(0)" json:"is_extracted"` + ExtractedTime *time.Time `orm:"column(extracted_time);type(datetime);null" json:"extracted_time"` + ExtractedPlatform *string `orm:"column(extracted_platform);size(32);null" json:"extracted_platform"` + CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"` + UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"` + DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"` +} + +func (m *PlatformAccountPoolWindsurf) TableName() string { + return "yz_platform_account_pool_windsurf" +} + +// PlatformAccountPoolCursor 号池表: yz_platform_account_pool_cursor +type PlatformAccountPoolCursor struct { + ID uint64 `orm:"column(id);pk;auto" json:"id"` + DataType string `orm:"column(data_type);size(32)" json:"data_type"` // account | tk | account_tk + Account string `orm:"column(account);size(128);default()" json:"account"` + Password string `orm:"column(password);size(255);default()" json:"password"` + Token string `orm:"column(token);type(text);null" json:"token"` + Remark string `orm:"column(remark);size(255);default()" json:"remark"` + IsExtracted int8 `orm:"column(is_extracted);default(0)" json:"is_extracted"` + ExtractedTime *time.Time `orm:"column(extracted_time);type(datetime);null" json:"extracted_time"` + ExtractedPlatform *string `orm:"column(extracted_platform);size(32);null" json:"extracted_platform"` + CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"` + UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"update_time"` + DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"` +} + +func (m *PlatformAccountPoolCursor) TableName() string { + return "yz_platform_account_pool_cursor" +} diff --git a/routers/platform/platform.go b/routers/platform/platform.go index a18d212..cdfae21 100644 --- a/routers/platform/platform.go +++ b/routers/platform/platform.go @@ -157,4 +157,23 @@ func Register() { beego.Router("/platform/storage/config", &controllers.QiniuUploadController{}, "get:GetStorageConfig") beego.Router("/platform/qiniu/token", &controllers.QiniuUploadController{}, "get:GetUploadToken") beego.Router("/platform/qiniu/save", &controllers.QiniuUploadController{}, "post:SaveFileRecord") + + // 账号池管理(cursor/windsurf/krio) + beego.Router("/platform/accountPool/cursor/list", &controllers.PlatformAccountPoolCursorController{}, "get:List") + beego.Router("/platform/accountPool/cursor/add", &controllers.PlatformAccountPoolCursorController{}, "post:Add") + beego.Router("/platform/accountPool/cursor/batchAdd", &controllers.PlatformAccountPoolCursorController{}, "post:BatchAdd") + beego.Router("/platform/accountPool/cursor/detail/:id", &controllers.PlatformAccountPoolCursorController{}, "get:Detail") + beego.Router("/platform/accountPool/cursor/extract", &controllers.PlatformAccountPoolCursorController{}, "post:Extract") + + beego.Router("/platform/accountPool/windsurf/list", &controllers.PlatformAccountPoolWindsurfController{}, "get:List") + beego.Router("/platform/accountPool/windsurf/add", &controllers.PlatformAccountPoolWindsurfController{}, "post:Add") + beego.Router("/platform/accountPool/windsurf/batchAdd", &controllers.PlatformAccountPoolWindsurfController{}, "post:BatchAdd") + beego.Router("/platform/accountPool/windsurf/detail/:id", &controllers.PlatformAccountPoolWindsurfController{}, "get:Detail") + beego.Router("/platform/accountPool/windsurf/extract", &controllers.PlatformAccountPoolWindsurfController{}, "post:Extract") + + beego.Router("/platform/accountPool/krio/list", &controllers.PlatformAccountPoolKrioController{}, "get:List") + beego.Router("/platform/accountPool/krio/add", &controllers.PlatformAccountPoolKrioController{}, "post:Add") + beego.Router("/platform/accountPool/krio/batchAdd", &controllers.PlatformAccountPoolKrioController{}, "post:BatchAdd") + beego.Router("/platform/accountPool/krio/detail/:id", &controllers.PlatformAccountPoolKrioController{}, "get:Detail") + beego.Router("/platform/accountPool/krio/extract", &controllers.PlatformAccountPoolKrioController{}, "post:Extract") }