392 lines
10 KiB
Go
392 lines
10 KiB
Go
package controllers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"io"
|
||
"server/models"
|
||
"strconv"
|
||
"strings"
|
||
|
||
beego "github.com/beego/beego/v2/server/web"
|
||
)
|
||
|
||
// AdminMenuController 后台菜单控制器
|
||
type AdminMenuController struct {
|
||
beego.Controller
|
||
}
|
||
|
||
type menuPayload struct {
|
||
Pid *int64 `json:"pid"`
|
||
Title *string `json:"title"`
|
||
Path *string `json:"path"`
|
||
ComponentPath *string `json:"component_path"`
|
||
Icon *string `json:"icon"`
|
||
Sort *int64 `json:"sort"`
|
||
Status *int8 `json:"status"`
|
||
IsVisible *int8 `json:"is_visible"`
|
||
IsPlatform *int8 `json:"is_platform"`
|
||
Type *int8 `json:"type"`
|
||
Permission *string `json:"permission"`
|
||
}
|
||
|
||
// GetMenu 获取指定用户可见的菜单列表(简化版:当前先忽略用户权限,返回全部启用且平台端菜单)
|
||
// 路由示例:GET /platform/menu/1
|
||
func (c *AdminMenuController) GetMenu() {
|
||
// 从路由参数中解析用户 ID,占位保留,方便后续按用户权限过滤
|
||
_ = c.Ctx.Input.Param(":id")
|
||
|
||
// 查询所有启用且标记为平台端的菜单
|
||
var menus []models.SystemMenu
|
||
qs := models.Orm.
|
||
QueryTable(new(models.SystemMenu)).
|
||
Filter("status", 1).
|
||
Filter("is_platform", 1)
|
||
_, err := qs.All(&menus)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 500,
|
||
"msg": "获取菜单失败: " + err.Error(),
|
||
"data": nil,
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 将平铺的菜单列表构建为树形结构
|
||
menuTree := buildMenuTree(menus, 0)
|
||
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 200,
|
||
"msg": "success",
|
||
"data": menuTree,
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// GetBackendMenu 获取租户端用户可见的菜单列表(简化版:当前先忽略用户权限,返回全部启用且租户端菜单)
|
||
// 路由示例:GET /backend/menu/1
|
||
func (c *AdminMenuController) GetBackendMenu() {
|
||
// 从路由参数中解析用户 ID,占位保留,方便后续按用户权限过滤
|
||
_ = c.Ctx.Input.Param(":id")
|
||
|
||
var menus []models.SystemMenu
|
||
qs := models.Orm.
|
||
QueryTable(new(models.SystemMenu)).
|
||
Filter("status", 1).
|
||
Filter("is_platform", 0)
|
||
_, err := qs.All(&menus)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 500,
|
||
"msg": "获取菜单失败: " + err.Error(),
|
||
"data": nil,
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
menuTree := buildMenuTree(menus, 0)
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 200,
|
||
"msg": "success",
|
||
"data": menuTree,
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// GetAllMenus 获取平台端全部菜单(用于菜单管理界面)
|
||
// 路由:GET /platform/allmenu
|
||
func (c *AdminMenuController) GetAllMenus() {
|
||
var menus []models.SystemMenu
|
||
cid, _ := c.GetInt("cid")
|
||
|
||
qs := models.Orm.QueryTable(new(models.SystemMenu))
|
||
// 菜单管理默认返回全量菜单;仅在明确传 cid 时按分类筛选
|
||
// cid: 1平台角色 -> 平台菜单;2租户角色 -> 租户菜单
|
||
if cid == 1 {
|
||
qs = qs.Filter("is_platform", 1)
|
||
} else if cid == 2 {
|
||
qs = qs.Filter("is_platform", 0)
|
||
}
|
||
_, err := qs.All(&menus)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 500,
|
||
"msg": "获取菜单失败: " + err.Error(),
|
||
"data": nil,
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
tree := buildMenuTree(menus, 0)
|
||
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 200,
|
||
"msg": "success",
|
||
"data": tree,
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// GetAllBackendMenus 获取租户端全部菜单(用于菜单管理界面)
|
||
// 路由:GET /backend/allmenu
|
||
func (c *AdminMenuController) GetAllBackendMenus() {
|
||
var menus []models.SystemMenu
|
||
_, err := models.Orm.QueryTable(new(models.SystemMenu)).
|
||
Filter("is_platform", 0).
|
||
All(&menus)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 500,
|
||
"msg": "获取菜单失败: " + err.Error(),
|
||
"data": nil,
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
tree := buildMenuTree(menus, 0)
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 200,
|
||
"msg": "success",
|
||
"data": tree,
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// menuNode 用于 JSON 返回的菜单结构
|
||
type menuNode struct {
|
||
ID uint64 `json:"id"`
|
||
Pid int64 `json:"pid"`
|
||
Title string `json:"title"`
|
||
Path string `json:"path,omitempty"`
|
||
ComponentPath string `json:"component_path,omitempty"`
|
||
Icon string `json:"icon,omitempty"`
|
||
Sort int64 `json:"sort"`
|
||
Status int8 `json:"status"`
|
||
IsVisible *int8 `json:"is_visible,omitempty"`
|
||
IsPlatform *int8 `json:"is_platform,omitempty"`
|
||
Type int8 `json:"type"`
|
||
Permission string `json:"permission,omitempty"`
|
||
Children []*menuNode `json:"children,omitempty"`
|
||
}
|
||
|
||
// buildMenuTree 将菜单列表构建成树结构
|
||
func buildMenuTree(menus []models.SystemMenu, pid int64) []*menuNode {
|
||
var tree []*menuNode
|
||
for _, m := range menus {
|
||
if m.Pid == pid {
|
||
node := &menuNode{
|
||
ID: m.ID,
|
||
Pid: m.Pid,
|
||
Title: m.Title,
|
||
Sort: m.Sort,
|
||
Status: m.Status,
|
||
IsVisible: m.IsVisible,
|
||
IsPlatform: m.IsPlatform,
|
||
Type: m.Type,
|
||
}
|
||
if m.Path != nil {
|
||
node.Path = *m.Path
|
||
}
|
||
if m.ComponentPath != nil {
|
||
node.ComponentPath = *m.ComponentPath
|
||
}
|
||
if m.Icon != nil {
|
||
node.Icon = *m.Icon
|
||
}
|
||
if m.Permission != nil {
|
||
node.Permission = *m.Permission
|
||
}
|
||
|
||
// 递归查找子菜单
|
||
children := buildMenuTree(menus, int64(m.ID))
|
||
if len(children) > 0 {
|
||
node.Children = children
|
||
}
|
||
tree = append(tree, node)
|
||
}
|
||
}
|
||
return tree
|
||
}
|
||
|
||
// UpdateMenuStatus 更新菜单状态
|
||
// 路由:PATCH /platform/menu/status/:id
|
||
func (c *AdminMenuController) UpdateMenuStatus() {
|
||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||
if err != nil || id == 0 {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "无效菜单ID"}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
var body struct {
|
||
Status *int8 `json:"status"`
|
||
}
|
||
rawBody, _ := io.ReadAll(c.Ctx.Request.Body)
|
||
if err := json.Unmarshal(rawBody, &body); err != nil || body.Status == nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
_, err = models.Orm.QueryTable(new(models.SystemMenu)).
|
||
Filter("id", id).
|
||
Update(map[string]interface{}{"status": *body.Status})
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "更新失败: " + err.Error()}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "success": true}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// CreateMenu 创建菜单
|
||
// 路由:POST /platform/createmenu
|
||
func (c *AdminMenuController) CreateMenu() {
|
||
payload, ok := c.parseMenuPayload(true)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
menu := models.SystemMenu{
|
||
Pid: valueInt64(payload.Pid, 0),
|
||
Title: strings.TrimSpace(valueString(payload.Title, "")),
|
||
Sort: valueInt64(payload.Sort, 0),
|
||
Status: valueInt8(payload.Status, 1),
|
||
IsVisible: ptrInt8(valueInt8(payload.IsVisible, 1)),
|
||
IsPlatform: ptrInt8(valueInt8(payload.IsPlatform, 1)),
|
||
Type: valueInt8(payload.Type, 1),
|
||
}
|
||
|
||
menu.Path = ptrString(valueString(payload.Path, ""))
|
||
menu.ComponentPath = ptrString(valueString(payload.ComponentPath, ""))
|
||
menu.Icon = ptrString(valueString(payload.Icon, ""))
|
||
menu.Permission = ptrString(valueString(payload.Permission, ""))
|
||
|
||
id, err := models.Orm.Insert(&menu)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "创建失败: " + err.Error()}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 200,
|
||
"msg": "创建成功",
|
||
"data": map[string]interface{}{"id": id},
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// UpdateMenu 更新菜单
|
||
// 路由:PUT /platform/updatemenu/:id
|
||
func (c *AdminMenuController) UpdateMenu() {
|
||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||
if err != nil || id == 0 {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "无效菜单ID"}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
payload, ok := c.parseMenuPayload(false)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
update := map[string]interface{}{
|
||
"pid": valueInt64(payload.Pid, 0),
|
||
"title": strings.TrimSpace(valueString(payload.Title, "")),
|
||
"path": valueString(payload.Path, ""),
|
||
"component_path": valueString(payload.ComponentPath, ""),
|
||
"icon": valueString(payload.Icon, ""),
|
||
"sort": valueInt64(payload.Sort, 0),
|
||
"status": valueInt8(payload.Status, 1),
|
||
"is_visible": valueInt8(payload.IsVisible, 1),
|
||
"is_platform": valueInt8(payload.IsPlatform, 1),
|
||
"type": valueInt8(payload.Type, 1),
|
||
"permission": valueString(payload.Permission, ""),
|
||
}
|
||
|
||
_, err = models.Orm.QueryTable(new(models.SystemMenu)).
|
||
Filter("id", id).
|
||
Update(update)
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "更新失败: " + err.Error()}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "更新成功"}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// DeleteMenu 删除菜单
|
||
// 路由:DELETE /platform/deletemenu/:id
|
||
func (c *AdminMenuController) DeleteMenu() {
|
||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||
if err != nil || id == 0 {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "无效菜单ID"}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
_, err = models.Orm.QueryTable(new(models.SystemMenu)).Filter("id", id).Delete()
|
||
if err != nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "删除失败: " + err.Error()}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "删除成功", "success": true}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
func (c *AdminMenuController) parseMenuPayload(needTitle bool) (*menuPayload, bool) {
|
||
rawBody, _ := io.ReadAll(c.Ctx.Request.Body)
|
||
var payload menuPayload
|
||
if err := json.Unmarshal(rawBody, &payload); err != nil {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
|
||
_ = c.ServeJSON()
|
||
return nil, false
|
||
}
|
||
if needTitle && strings.TrimSpace(valueString(payload.Title, "")) == "" {
|
||
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "菜单名称不能为空"}
|
||
_ = c.ServeJSON()
|
||
return nil, false
|
||
}
|
||
return &payload, true
|
||
}
|
||
|
||
func valueString(v *string, def string) string {
|
||
if v == nil {
|
||
return def
|
||
}
|
||
return *v
|
||
}
|
||
|
||
func valueInt8(v *int8, def int8) int8 {
|
||
if v == nil {
|
||
return def
|
||
}
|
||
return *v
|
||
}
|
||
|
||
func valueInt64(v *int64, def int64) int64 {
|
||
if v == nil {
|
||
return def
|
||
}
|
||
return *v
|
||
}
|
||
|
||
func ptrString(v string) *string {
|
||
return &v
|
||
}
|
||
|
||
func ptrInt8(v int8) *int8 {
|
||
return &v
|
||
}
|
||
|