Files
yunzerwebsiteallinone/go/controllers/platform_modules.go
T
2026-11-03 11:13:59 +08:00

481 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()
}