package controllers import ( "encoding/json" "io" "strconv" "strings" "time" "server/models" "server/pkg/identity" "server/pkg/jwtutil" "server/services" beego "github.com/beego/beego/v2/server/web" ) // validatePlatforms 校验展示端取值,返回空串表示合法。 // 只允许 web / app,避免出现拼错的值导致菜单在某端永远不可见。 func validatePlatforms(list []string) string { for _, s := range list { switch strings.ToLower(strings.TrimSpace(s)) { case models.PlatformWeb, models.PlatformApp: default: if strings.TrimSpace(s) == "" { continue } return "展示端取值非法,仅支持 web(Web端)与 app(移动端)" } } return "" } // platformList 把模块展示端配置输出给管理端:统一返回数组,空配置回落为全端 func platformList(m *models.SystemModules) []string { if m == nil { return []string{models.PlatformWeb, models.PlatformApp} } list := services.ParsePlatforms(m.Platforms) if len(list) == 0 { return []string{models.PlatformWeb, models.PlatformApp} } return list } // PlatformModulesController 模块管理(yz_system_modules) type PlatformModulesController struct { beego.Controller } func (c *PlatformModulesController) modulesClaims() (*jwtutil.Claims, error) { return identity.ClaimsByPath(c.Ctx.Request.Header.Get("Authorization"), c.Ctx.Request.URL.Path) } func (c *PlatformModulesController) jsonErr(httpStatus, bizCode int, msg string) { c.Ctx.Output.SetStatus(httpStatus) c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg} _ = c.ServeJSON() } // GetList GET /platform/modules/list func (c *PlatformModulesController) GetList() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } var rows []models.SystemModules _, err := models.Orm.QueryTable(new(models.SystemModules)). Filter("delete_time__isnull", true). OrderBy("sort", "id"). 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, map[string]interface{}{ "id": rows[i].ID, "mid": rows[i].Mid, "name": rows[i].Name, "code": rows[i].Code, "path": rows[i].Path, "icon": rows[i].Icon, "description": rows[i].Description, "type": rows[i].Type, "sort": rows[i].Sort, "status": rows[i].Status, "is_show": rows[i].IsShow, "require_login": rows[i].RequireLogin, "platforms": platformList(&rows[i]), }) } c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "获取成功", "data": map[string]interface{}{ "list": list, "total": len(list), }, } _ = c.ServeJSON() } // GetTenantList GET /platform/modules/getTenantList // 兼容旧接口命名:返回当前账号可见的模块。当前实现:返回 status=1 且 is_show=1 的全部模块。 func (c *PlatformModulesController) GetTenantList() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } var rows []models.SystemModules _, err := models.Orm.QueryTable(new(models.SystemModules)). Filter("delete_time__isnull", true). Filter("status", 1). Filter("is_show", 1). OrderBy("sort", "id"). All(&rows) if err != nil { c.jsonErr(500, 500, "获取失败:"+err.Error()) return } c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "获取成功", "data": map[string]interface{}{ "list": rows, "total": len(rows), }, } _ = c.ServeJSON() } // GetDetail GET /platform/modules/:id func (c *PlatformModulesController) GetDetail() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil || id == 0 { c.jsonErr(400, 400, "参数错误") return } var row models.SystemModules err = models.Orm.QueryTable(new(models.SystemModules)). Filter("id", id). Filter("delete_time__isnull", true). One(&row) if err != nil { c.jsonErr(404, 404, "模块不存在") return } // 与 GetList 保持一致的规范化输出:platforms 统一为数组、带上 require_login。 // 否则详情回填时 platforms 是原始 JSON 字符串,编辑提交会因 []string 反序列化失败报 400。 c.Data["json"] = map[string]interface{}{ "code": 200, "msg": "获取成功", "data": map[string]interface{}{ "id": row.ID, "mid": row.Mid, "name": row.Name, "code": row.Code, "path": row.Path, "icon": row.Icon, "description": row.Description, "type": row.Type, "sort": row.Sort, "status": row.Status, "is_show": row.IsShow, "require_login": row.RequireLogin, "platforms": platformList(&row), }, } _ = c.ServeJSON() } type modulePayload struct { Mid *uint64 `json:"mid"` Name string `json:"name"` Code string `json:"code"` Path string `json:"path"` Icon string `json:"icon"` Description string `json:"description"` Type int `json:"type"` Sort int `json:"sort"` Status int8 `json:"status"` IsShow int8 `json:"is_show"` Platforms []string `json:"platforms"` // 展示端:["web"] ["app"] ["web","app"];空=全端 RequireLogin *int8 `json:"require_login"` // 是否必须登录:1=必须 0=可免登录;指针以区分「未传」(默认 1) } // resolveRequireLogin 未传该字段时回落为 1(必须登录),保持既有行为不变。 func resolveRequireLogin(v *int8) int8 { if v == nil { return 1 } if *v != 0 && *v != 1 { return 1 } return *v } // Add POST /platform/modules func (c *PlatformModulesController) Add() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.jsonErr(400, 400, "参数错误") return } var p modulePayload if err := json.Unmarshal(raw, &p); err != nil { c.jsonErr(400, 400, "参数错误") return } if errMsg := validatePlatforms(p.Platforms); errMsg != "" { c.jsonErr(400, 400, errMsg) return } p.Name = strings.TrimSpace(p.Name) p.Code = strings.TrimSpace(p.Code) if p.Name == "" || p.Code == "" { c.jsonErr(400, 400, "模块名称和编码不能为空") return } // code 唯一(排除软删) cnt, _ := models.Orm.QueryTable(new(models.SystemModules)). Filter("code", p.Code). Filter("delete_time__isnull", true). Count() if cnt > 0 { c.jsonErr(400, 400, "模块编码已存在") return } now := time.Now() platforms := services.NormalizePlatforms(p.Platforms) row := &models.SystemModules{ Mid: p.Mid, Name: p.Name, Code: p.Code, Path: strings.TrimSpace(p.Path), Icon: strings.TrimSpace(p.Icon), Description: strings.TrimSpace(p.Description), Type: p.Type, Sort: p.Sort, Status: p.Status, IsShow: p.IsShow, RequireLogin: resolveRequireLogin(p.RequireLogin), CreateTime: &now, UpdateTime: &now, } if platforms != "" { row.Platforms = &platforms } id, err := models.Orm.Insert(row) if err != nil { c.jsonErr(500, 500, "添加失败:"+err.Error()) return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "添加成功", "data": map[string]interface{}{"id": uint64(id)}} _ = c.ServeJSON() } // Edit PUT /platform/modules/:id func (c *PlatformModulesController) Edit() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil || id == 0 { c.jsonErr(400, 400, "参数错误") return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.jsonErr(400, 400, "参数错误") return } var p modulePayload if err := json.Unmarshal(raw, &p); err != nil { c.jsonErr(400, 400, "参数错误") return } p.Name = strings.TrimSpace(p.Name) p.Code = strings.TrimSpace(p.Code) if p.Name == "" || p.Code == "" { c.jsonErr(400, 400, "模块名称和编码不能为空") return } if errMsg := validatePlatforms(p.Platforms); errMsg != "" { c.jsonErr(400, 400, errMsg) return } // code 唯一(排除自身与软删) cnt, _ := models.Orm.QueryTable(new(models.SystemModules)). Filter("code", p.Code). Filter("id__ne", id). Filter("delete_time__isnull", true). Count() if cnt > 0 { c.jsonErr(400, 400, "模块编码已存在") return } now := time.Now() // 展示端为空串表示「全端」,需显式落库以覆盖历史值 up := map[string]interface{}{ "mid": p.Mid, "name": p.Name, "code": p.Code, "path": strings.TrimSpace(p.Path), "icon": strings.TrimSpace(p.Icon), "description": strings.TrimSpace(p.Description), "type": p.Type, "sort": p.Sort, "status": p.Status, "is_show": p.IsShow, "require_login": resolveRequireLogin(p.RequireLogin), "platforms": services.NormalizePlatforms(p.Platforms), "update_time": now, } n, err := models.Orm.QueryTable(new(models.SystemModules)). Filter("id", id). Filter("delete_time__isnull", true). Update(up) if err != nil { c.jsonErr(500, 500, "编辑失败:"+err.Error()) return } if n == 0 { c.jsonErr(404, 404, "模块不存在") return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "编辑成功"} _ = c.ServeJSON() } // Delete DELETE /platform/modules/:id(软删) func (c *PlatformModulesController) Delete() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil || id == 0 { c.jsonErr(400, 400, "参数错误") return } now := time.Now() n, err := models.Orm.QueryTable(new(models.SystemModules)). 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.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功"} _ = c.ServeJSON() } // BatchDelete POST /platform/modules/batchDelete body:{ids:[]} func (c *PlatformModulesController) BatchDelete() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.jsonErr(400, 400, "参数错误") return } var p struct { IDs []uint64 `json:"ids"` } if err := json.Unmarshal(raw, &p); err != nil || len(p.IDs) == 0 { c.jsonErr(400, 400, "请选择要删除的模块") return } now := time.Now() _, err = models.Orm.QueryTable(new(models.SystemModules)). Filter("id__in", p.IDs). 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 } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "批量删除成功"} _ = c.ServeJSON() } // ChangeStatus POST /platform/modules/status body:{id,status} // 兼容前端:这里的 status 实际用于切换 is_show(显示开关)。 func (c *PlatformModulesController) ChangeStatus() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.jsonErr(400, 400, "参数错误") return } var p struct { ID uint64 `json:"id"` Status int8 `json:"status"` } if err := json.Unmarshal(raw, &p); err != nil || p.ID == 0 { c.jsonErr(400, 400, "参数错误") return } if p.Status != 0 && p.Status != 1 { p.Status = 1 } now := time.Now() n, err := models.Orm.QueryTable(new(models.SystemModules)). Filter("id", p.ID). Filter("delete_time__isnull", true). Update(map[string]interface{}{"is_show": p.Status, "update_time": now}) if err != nil { c.jsonErr(500, 500, "状态修改失败:"+err.Error()) return } if n == 0 { c.jsonErr(404, 404, "模块不存在") return } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success"} _ = c.ServeJSON() } // GetSelectList GET /platform/modules/select/list func (c *PlatformModulesController) GetSelectList() { if _, err := c.modulesClaims(); err != nil { code := identity.Status(err) c.jsonErr(code, code, err.Error()) return } var rows []models.SystemModules _, err := models.Orm.QueryTable(new(models.SystemModules)). Filter("delete_time__isnull", true). Filter("status", 1). OrderBy("sort", "id"). All(&rows, "ID", "Name", "Code") 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, map[string]interface{}{ "id": rows[i].ID, "name": rows[i].Name, "code": rows[i].Code, }) } c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": list} _ = c.ServeJSON() }