package controllers import ( "encoding/json" "fmt" "io" "regexp" "strconv" "strings" "time" "server/models" "server/pkg/jwtutil" "github.com/beego/beego/v2/client/orm" beego "github.com/beego/beego/v2/server/web" ) // PlatformDomainPoolController 主域名池管理 type PlatformDomainPoolController struct { beego.Controller } // PlatformTenantDomainController 租户域名管理 type PlatformTenantDomainController struct { beego.Controller } func requirePlatform(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 jsonErr(c *beego.Controller, httpStatus, bizCode int, msg string) { c.Ctx.Output.SetStatus(httpStatus) c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg} _ = c.ServeJSON() } // ===== 主域名池 ===== // Index GET /platform/domain/pool/index?page=&pageSize=&main_domain=&status= func (c *PlatformDomainPoolController) Index() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } page, _ := c.GetInt("page", 1) pageSize, _ := c.GetInt("pageSize", 10) if page < 1 { page = 1 } if pageSize < 1 { pageSize = 10 } if pageSize > 200 { pageSize = 200 } mainDomain := strings.TrimSpace(c.GetString("main_domain")) statusStr := strings.TrimSpace(c.GetString("status")) qs := models.Orm.QueryTable(new(models.SystemDomainPool)).Filter("delete_time__isnull", true) if mainDomain != "" { qs = qs.Filter("main_domain__icontains", mainDomain) } if statusStr != "" { if st, err := strconv.Atoi(statusStr); err == nil { qs = qs.Filter("status", st) } } total, err := qs.Count() if err != nil { jsonErr(&c.Controller, 500, 500, "获取主域名池失败: "+err.Error()) return } var rows []models.SystemDomainPool _, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows) if err != nil { jsonErr(&c.Controller, 500, 500, "获取主域名池失败: "+err.Error()) return } list := make([]map[string]interface{}, 0, len(rows)) for i := range rows { item := map[string]interface{}{ "id": rows[i].ID, "main_domain": rows[i].MainDomain, "status": rows[i].Status, "create_time": rows[i].CreateTime.Format("2006-01-02 15:04:05"), "update_time": "", } if rows[i].UpdateTime != nil { item["update_time"] = rows[i].UpdateTime.Format("2006-01-02 15:04:05") } list = append(list, item) } c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "success", "data": map[string]interface{}{ "list": list, "total": total, }, } _ = c.ServeJSON() } // GetEnabledDomains GET /platform/domain/pool/getEnabledDomains func (c *PlatformDomainPoolController) GetEnabledDomains() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } var rows []models.SystemDomainPool _, err := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("status", 1). Filter("delete_time__isnull", true). OrderBy("-id"). All(&rows) if err != nil { jsonErr(&c.Controller, 500, 500, "获取主域名失败: "+err.Error()) return } out := make([]map[string]interface{}, 0, len(rows)) for i := range rows { out = append(out, map[string]interface{}{ "id": rows[i].ID, "main_domain": rows[i].MainDomain, "status": rows[i].Status, }) } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": out} _ = c.ServeJSON() } type domainPoolPayload struct { ID uint64 `json:"id"` MainDomain string `json:"main_domain"` Status int8 `json:"status"` } // Create POST /platform/domain/pool/create func (c *PlatformDomainPoolController) Create() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p domainPoolPayload if err := json.Unmarshal(raw, &p); err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } md := strings.TrimSpace(p.MainDomain) if md == "" { jsonErr(&c.Controller, 400, 400, "主域名不能为空") return } if p.Status != 0 && p.Status != 1 { p.Status = 1 } // 简单去重 cnt, _ := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("main_domain", md). Filter("delete_time__isnull", true). Count() if cnt > 0 { jsonErr(&c.Controller, 400, 400, "主域名已存在") return } row := &models.SystemDomainPool{MainDomain: md, Status: p.Status} if _, err := models.Orm.Insert(row); err != nil { jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "创建成功"} _ = c.ServeJSON() } // Update POST /platform/domain/pool/update func (c *PlatformDomainPoolController) Update() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p domainPoolPayload if err := json.Unmarshal(raw, &p); err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } if p.ID == 0 { jsonErr(&c.Controller, 400, 400, "id 不能为空") return } md := strings.TrimSpace(p.MainDomain) if md == "" { jsonErr(&c.Controller, 400, 400, "主域名不能为空") return } if p.Status != 0 && p.Status != 1 { p.Status = 1 } now := time.Now() n, err := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("id", p.ID). Filter("delete_time__isnull", true). Update(map[string]interface{}{"main_domain": md, "status": p.Status, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "记录不存在") return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "更新成功"} _ = c.ServeJSON() } // Delete DELETE /platform/domain/pool/delete/:id func (c *PlatformDomainPoolController) Delete() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil || id == 0 { jsonErr(&c.Controller, 400, 400, "无效ID") return } now := time.Now() n, err := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "记录不存在") return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"} _ = c.ServeJSON() } // ToggleStatus POST /platform/domain/pool/toggleStatus body:{id} func (c *PlatformDomainPoolController) ToggleStatus() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p struct { ID uint64 `json:"id"` } if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 { jsonErr(&c.Controller, 400, 400, "参数错误") return } var row models.SystemDomainPool if err := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("id", p.ID). Filter("delete_time__isnull", true). One(&row); err != nil { jsonErr(&c.Controller, 404, 404, "记录不存在") return } newStatus := int8(1) if row.Status == 1 { newStatus = 0 } now := time.Now() _, err = models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("id", p.ID). Update(map[string]interface{}{"status": newStatus, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "切换失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"} _ = c.ServeJSON() } // ===== 租户域名 ===== // Index GET /platform/domain/tenant/index?page=&pageSize=&tid=&status=&sub_domain= func (c *PlatformTenantDomainController) Index() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } page, _ := c.GetInt("page", 1) pageSize, _ := c.GetInt("pageSize", 10) if page < 1 { page = 1 } if pageSize < 1 { pageSize = 10 } if pageSize > 200 { pageSize = 200 } tid, _ := c.GetUint64("tid") statusStr := strings.TrimSpace(c.GetString("status")) subDomain := strings.TrimSpace(c.GetString("sub_domain")) qs := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("delete_time__isnull", true) if tid > 0 { qs = qs.Filter("tid", tid) } if statusStr != "" { if st, err := strconv.Atoi(statusStr); err == nil { qs = qs.Filter("status", st) } } if subDomain != "" { qs = qs.Filter("sub_domain__icontains", subDomain) } total, err := qs.Count() if err != nil { jsonErr(&c.Controller, 500, 500, "获取租户域名失败: "+err.Error()) return } var rows []models.SystemTenantDomain _, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows) if err != nil { jsonErr(&c.Controller, 500, 500, "获取租户域名失败: "+err.Error()) return } list := make([]models.SystemTenantDomain, 0, len(rows)) list = append(list, rows...) c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "success", "data": map[string]interface{}{"list": list, "total": total}, } _ = c.ServeJSON() } // MyDomains GET /platform/domain/tenant/myDomains?tid=1 func (c *PlatformTenantDomainController) MyDomains() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } tid, _ := c.GetUint64("tid") if tid == 0 { jsonErr(&c.Controller, 400, 400, "租户ID不能为空") return } var rows []models.SystemTenantDomain _, err := models.Orm.QueryTable(new(models.SystemTenantDomain)). Filter("tid", tid). Filter("delete_time__isnull", true). OrderBy("-id"). All(&rows) if err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": rows} _ = c.ServeJSON() } var subDomainRe = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$`) // Apply POST /platform/domain/tenant/apply body:{tid,sub_domain,main_domain} func (c *PlatformTenantDomainController) Apply() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p struct { Tid uint64 `json:"tid"` SubDomain string `json:"sub_domain"` MainDomain string `json:"main_domain"` } if err := json.Unmarshal(raw, &p); err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } if p.Tid == 0 { jsonErr(&c.Controller, 400, 400, "租户ID不能为空") return } sub := strings.TrimSpace(p.SubDomain) main := strings.TrimSpace(p.MainDomain) if sub == "" { jsonErr(&c.Controller, 400, 400, "二级域名前缀不能为空") return } if main == "" { jsonErr(&c.Controller, 400, 400, "请选择主域名") return } if !subDomainRe.MatchString(sub) { jsonErr(&c.Controller, 400, 400, "二级域名前缀格式不正确") return } // 该租户是否已有域名 cnt, _ := models.Orm.QueryTable(new(models.SystemTenantDomain)). Filter("tid", p.Tid). Filter("delete_time__isnull", true). Count() if cnt > 0 { jsonErr(&c.Controller, 400, 400, "该租户已有域名,请删除后再次申请") return } // 主域名存在且启用 var pool models.SystemDomainPool if err := models.Orm.QueryTable(new(models.SystemDomainPool)). Filter("main_domain", main). Filter("status", 1). Filter("delete_time__isnull", true). One(&pool); err != nil { jsonErr(&c.Controller, 400, 400, "主域名不存在或已禁用") return } // 二级域名是否已被使用(同主域名下) used, _ := models.Orm.QueryTable(new(models.SystemTenantDomain)). Filter("sub_domain", sub). Filter("main_domain", main). Filter("delete_time__isnull", true). Count() if used > 0 { jsonErr(&c.Controller, 400, 400, "该二级域名已被使用") return } full := sub + "." + main now := time.Now() tid := p.Tid row := &models.SystemTenantDomain{ Tid: &tid, SubDomain: &sub, MainDomain: &main, FullDomain: &full, Status: 0, CreateTime: now, UpdateTime: &now, } id, err := models.Orm.Insert(row) if err != nil { jsonErr(&c.Controller, 500, 500, "申请失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "申请提交成功,等待审核", "data": map[string]interface{}{"id": uint64(id)}} _ = c.ServeJSON() } // Audit POST /platform/domain/tenant/audit body:{id,action} action=approve/reject func (c *PlatformTenantDomainController) Audit() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p struct { ID uint64 `json:"id"` Action string `json:"action"` } if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 { jsonErr(&c.Controller, 400, 400, "参数错误") return } var row models.SystemTenantDomain if err := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).One(&row); err != nil { jsonErr(&c.Controller, 404, 404, "域名不存在") return } if row.Status != 0 { jsonErr(&c.Controller, 400, 400, "该域名已审核过了") return } newStatus := 2 msg := "已拒绝" if strings.ToLower(strings.TrimSpace(p.Action)) == "approve" { newStatus = 1 msg = "审核通过" } now := time.Now() _, err = models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).Update(map[string]interface{}{ "status": newStatus, "update_time": now, }) if err != nil { jsonErr(&c.Controller, 500, 500, "审核失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": msg} _ = c.ServeJSON() } // ToggleStatus POST /platform/domain/tenant/toggleStatus body:{id} func (c *PlatformTenantDomainController) ToggleStatus() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { jsonErr(&c.Controller, 400, 400, "参数错误") return } var p struct { ID uint64 `json:"id"` } if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 { jsonErr(&c.Controller, 400, 400, "参数错误") return } var row models.SystemTenantDomain if err := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).One(&row); err != nil { jsonErr(&c.Controller, 404, 404, "域名不存在") return } if row.Status == 0 { jsonErr(&c.Controller, 400, 400, "审核中不可操作") return } newStatus := 2 if row.Status == 2 { newStatus = 1 } now := time.Now() _, err = models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("id", p.ID).Update(map[string]interface{}{ "status": newStatus, "update_time": now, }) if err != nil { jsonErr(&c.Controller, 500, 500, "操作失败: "+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"} _ = c.ServeJSON() } // Delete DELETE /platform/domain/tenant/delete/:id func (c *PlatformTenantDomainController) Delete() { if _, err := requirePlatform(&c.Controller); err != nil { jsonErr(&c.Controller, 401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil || id == 0 { jsonErr(&c.Controller, 400, 400, "参数错误") return } now := time.Now() n, err := models.Orm.QueryTable(new(models.SystemTenantDomain)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "域名不存在") return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"} _ = c.ServeJSON() } // 用于复杂筛选时可扩展:当前保留 orm.Condition import,避免被 gofmt 删除 var _ = orm.NewCondition