作者 yangfu

add menu

... ... @@ -14,7 +14,7 @@ type CreateMenuCommand struct {
// 菜单编码 SYSTEM_USER_EDIT / 100101 (字符编码)
Code string `json:"code" valid:"Required"`
// 权限编码 users:edit
AccessCode string `json:"accessCode" valid:"Required"`
AccessCode string `json:"accessCode"`
// 菜单类型 (目录catalog、菜单menu、按钮button)
MenuType string `json:"menuType" valid:"Required"`
// 菜单图标
... ... @@ -24,7 +24,7 @@ type CreateMenuCommand struct {
// 菜单说明
Desc string `json:"desc,omitempty"`
// 菜单是否公开状态,[0:隐藏],[1:显示],默认显示
IsPublish int `json:"isPublish" valid:"Required"`
IsPublish int `json:"isPublish"`
}
func (createMenuCommand *CreateMenuCommand) Valid(validation *validation.Validation) {
... ...
... ... @@ -9,10 +9,12 @@ import (
type ListMenuQuery struct {
// 菜单类别 web app
MenuCategory string `json:"menuCategory,omitempty"`
// 菜单父级id 0:查询所有 n:父级id为n的菜单列表
MenuParentId int64 `json:"parentId,omitempty"`
// 菜单父级id 0:查询所有 n:parent_id为n的菜单列表
ParentId int64 `json:"parentId,omitempty"`
// 菜单名称过滤
MenuName string `json:"menuName,omitempty"`
// 结构类型 树型:tree 列表型:list
StructType string `json:"structType,omitempty"`
// 查询偏离量
Offset int `json:"offset"`
// 查询限制
... ...
... ... @@ -8,6 +8,7 @@ import (
"gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/application/menu/command"
"gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/application/menu/query"
"gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/domain"
"gitlab.fjmaimaimai.com/mmm-go-pp/terms/pkg/infrastructure/common"
"strconv"
)
... ... @@ -49,14 +50,24 @@ func (menuService *MenuService) CreateMenu(createMenuCommand *command.CreateMenu
} else {
menuRepository = value
}
// 1.菜单类型验证
if newMenu.ValidMenuType() {
return nil, application.ThrowError(application.ARG_ERROR, domain.ErrorMenuType.Error())
}
// 2.菜单编码验证
if menu, err := menuRepository.FindOne(map[string]interface{}{"code": createMenuCommand.Code}); err == nil && menu != nil {
return nil, application.ThrowError(application.ARG_ERROR, fmt.Sprintf("菜单编码:%v已重复,请重新输入", createMenuCommand.Code))
}
// 3.更新菜单路径
if newMenu.ParentId > 0 {
if pMenu, err := menuRepository.FindOne(map[string]interface{}{"menuId": newMenu.ParentId}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "父级菜单不存在")
} else {
newMenu.ParentPath = pMenu.GetParentPath()
newMenu.Category = pMenu.GetCategory()
}
}
// 4.保存菜单项
if menu, err := menuRepository.Save(newMenu); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
... ... @@ -127,7 +138,7 @@ func (menuService *MenuService) ListMenu(listMenuQuery *query.ListMenuQuery) (in
} else {
menuRepository = value
}
queryOptions := tool_funs.SimpleStructToMap(listMenuQuery)
queryOptions := common.SimpleStructToMap(listMenuQuery)
if len(listMenuQuery.MenuCategory) > 0 {
queryOptions["code"] = ""
if m, e := menuRepository.FindOne(map[string]interface{}{"code": listMenuQuery.MenuCategory}); e == nil && m != nil {
... ... @@ -140,6 +151,18 @@ func (menuService *MenuService) ListMenu(listMenuQuery *query.ListMenuQuery) (in
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
// 树形返回
if listMenuQuery.StructType == domain.StructTree {
var treeNodes = make([]domain.TreeNode, len(menus))
for i := 0; i < len(menus); i++ {
treeNodes[i] = menus[i]
}
return map[string]interface{}{
"count": count,
"menus": domain.NewTrees(treeNodes).Nodes,
}, nil
}
// 列表返回
return map[string]interface{}{
"count": count,
"menus": menus,
... ... @@ -170,6 +193,7 @@ func (menuService *MenuService) RemoveMenu(removeMenuCommand *command.RemoveMenu
} else {
menuRepository = value
}
// 1.节点是否存在
menu, err := menuRepository.FindOne(map[string]interface{}{"menuId": removeMenuCommand.MenuId})
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
... ... @@ -177,6 +201,10 @@ func (menuService *MenuService) RemoveMenu(removeMenuCommand *command.RemoveMenu
if menu == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(removeMenuCommand.MenuId)))
}
// 2. 是否存在子节点
if m, err := menuRepository.FindOne(map[string]interface{}{"parentId": menu.MenuId}); err == nil && m != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "下级菜单不为空")
}
if menu, err := menuRepository.Remove(menu); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
... ... @@ -217,7 +245,13 @@ func (menuService *MenuService) UpdateMenu(updateMenuCommand *command.UpdateMenu
if menu == nil {
return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(updateMenuCommand.MenuId)))
}
// 父级节点有发生更新
// 1.验证code是否有重复的情况
if menu.Code != updateMenuCommand.Code {
if m, e := menuRepository.FindOne(map[string]interface{}{"code": updateMenuCommand.Code}); e == nil && m.MenuId != menu.MenuId {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
}
// 2.验证父级节点是否有发生更新
if updateMenuCommand.ParentId != menu.ParentId && (updateMenuCommand.ParentId != 0 && menu.ParentId != 0) {
var oldParentFullPath, newParentFullPath = menu.GetFullPath(), menu.GetFullPath()
var oldParentPath = menu.ParentPath
... ...
... ... @@ -5,6 +5,7 @@ import "os"
const SERVICE_NAME = "terms.base"
var LOG_LEVEL = "debug"
var EnableCaching = false
func init() {
if os.Getenv("LOG_LEVEL") != "" {
... ...
package domain
import (
"errors"
"fmt"
"strconv"
"strings"
)
var PathSegment = ","
const PathSegment = ","
var (
Catalog MenuType = "catalog" // 目录
Menu_ MenuType = "menu" // 菜单
Button MenuType = "button" // 按钮
)
var (
ErrorMenuType = errors.New(fmt.Sprintf("菜单类型有误 可选值 %v、%v、%v", Catalog, Menu_, Button))
)
// 菜单类型
type MenuType string
// 系统菜单
type Menu struct {
... ... @@ -128,3 +142,19 @@ func (menu *Menu) UpdateParentPath(old, new string) {
}
menu.ParentPath = strings.Replace(menu.ParentPath, old, new, 1)
}
func (menu *Menu) ValidMenuType() bool {
mt := MenuType(menu.MenuType)
if mt == Catalog || mt == Menu_ || mt == Button {
return true
}
return false
}
// 实现 TreeNode
func (menu *Menu) PID() string {
return menu.ParentPath
}
func (menu *Menu) ID() string {
return menu.GetFullPath()
}
... ...
package domain
const (
StructTree = "tree"
StructList = "list"
)
type TreeNode interface {
PID() string
ID() string
}
type Tree struct {
Node TreeNode `json:"node"`
Nodes []*Tree `json:"nodes"`
}
func traverse(tree *Tree, node TreeNode) bool {
list := tree.Nodes
var match bool = false
for i := range list {
id, pid := list[i].Node.ID(), node.PID() //list[i].Node.PID() == node.ID()
if pid == id {
list[i].Nodes = append(list[i].Nodes, NewTree(node))
return true
}
if match || traverse(list[i], node) {
match = true
break
}
}
return match
}
func NewTrees(nodes []TreeNode) *Tree {
var tree = &Tree{
Node: nil,
Nodes: make([]*Tree, 0),
}
for i := range nodes {
match := traverse(tree, nodes[i])
if !match {
tree.Nodes = append(tree.Nodes, NewTree(nodes[i]))
}
}
return tree
}
func NewTree(node TreeNode) *Tree {
return &Tree{
Node: node,
Nodes: make([]*Tree, 0),
}
}
... ...
package common
import (
"github.com/linmadan/egglib-go/utils/string_convert"
"reflect"
)
func SimpleStructToMap(toMapStruct interface{}) map[string]interface{} {
m := ObjectToMap(toMapStruct)
if pageNumber, ok := m["pageNumber"]; ok {
var pageSize int64
if _, ok := m["pageSize"]; ok {
pageSize = m["pageSize"].(int64)
} else {
pageSize = 20
}
m["offset"] = (pageNumber.(int64) - 1) * pageSize
m["limit"] = pageSize
}
return m
}
func ObjectToMap(o interface{}) map[string]interface{} {
if o == nil {
return nil
}
value := reflect.ValueOf(o)
if value.Kind() != reflect.Ptr {
return nil
}
elem := value.Elem()
relType := elem.Type()
m := make(map[string]interface{})
for i := 0; i < relType.NumField(); i++ {
field := relType.Field(i)
if elem.Field(i).IsZero() {
continue
}
m[string_convert.CamelCase(field.Name, false, false)] = elem.Field(i).Interface()
}
return m
}
... ...
... ... @@ -163,6 +163,7 @@ func (repository *MenuRepository) Find(queryOptions map[string]interface{}) (int
if v, ok := queryOptions["menuName"]; ok {
query.Where(fmt.Sprintf("menu_name like '%%%v%%'", v))
}
query.SetWhereByQueryOption("parent_id = ?", "parentId")
query.SetOffsetAndLimit(20)
query.SetOrderDirect("menu_id", "asc")
if count, err := query.SelectAndCount(); err != nil {
... ...
... ... @@ -56,8 +56,9 @@ func (controller *MenuController) ListMenu() {
limit, _ := controller.GetInt("limit")
listMenuQuery.Limit = limit
listMenuQuery.MenuCategory = controller.GetString("menuCategory")
listMenuQuery.MenuParentId, _ = controller.GetInt64("parentId", 0)
listMenuQuery.ParentId, _ = controller.GetInt64("parentId", 0)
listMenuQuery.MenuName = controller.GetString("menuName")
listMenuQuery.StructType = controller.GetString("structType")
data, err := menuService.ListMenu(listMenuQuery)
controller.Response(data, err)
}
... ...