作者 yangfu

add menu

... ... @@ -10,11 +10,11 @@ metadata:
required: false
type:
primitive: string
- name: menuParentId
- name: parentId
description: 菜单父级id 0:查询所有 n:父级id为n的菜单列表
required: false
type:
primitive: string
primitive: int64
- name: menuName
description: 菜单名称过滤
required: false
... ...
... ... @@ -9,6 +9,8 @@ import (
type UpdateMenuCommand struct {
// 菜单编号
MenuId int64 `json:"menuId" valid:"Required"`
// 父级id
ParentId int64 `json:"parentId,omitempty"`
// 菜单名称
MenuName string `json:"menuName" valid:"Required"`
// 菜单编码 SYSTEM_USER_EDIT / 100101 (字符编码)
... ...
... ... @@ -10,11 +10,11 @@ type ListMenuQuery struct {
// 菜单类别 web app
MenuCategory string `json:"menuCategory,omitempty"`
// 菜单父级id 0:查询所有 n:父级id为n的菜单列表
MenuParentId string `json:"menuParentId,omitempty"`
MenuParentId int64 `json:"parentId,omitempty"`
// 菜单名称过滤
MenuName string `json:"menuName,omitempty"`
// 查询偏离量
Offset int `json:"offset" valid:"Required"`
Offset int `json:"offset"`
// 查询限制
Limit int `json:"limit" valid:"Required"`
}
... ...
... ... @@ -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"
"strconv"
)
// 菜单服务
... ... @@ -48,6 +49,14 @@ func (menuService *MenuService) CreateMenu(createMenuCommand *command.CreateMenu
} else {
menuRepository = value
}
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())
} else {
newMenu.ParentPath = pMenu.GetParentPath()
newMenu.Category = pMenu.GetCategory()
}
}
if menu, err := menuRepository.Save(newMenu); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
... ... @@ -118,7 +127,14 @@ func (menuService *MenuService) ListMenu(listMenuQuery *query.ListMenuQuery) (in
} else {
menuRepository = value
}
if count, menus, err := menuRepository.Find(tool_funs.SimpleStructToMap(listMenuQuery)); err != nil {
queryOptions := tool_funs.SimpleStructToMap(listMenuQuery)
if len(listMenuQuery.MenuCategory) > 0 {
queryOptions["code"] = ""
if m, e := menuRepository.FindOne(map[string]interface{}{"code": listMenuQuery.MenuCategory}); e == nil && m != nil {
queryOptions["category"] = strconv.Itoa(int(m.MenuId))
}
}
if count, menus, err := menuRepository.Find(queryOptions); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
... ... @@ -201,6 +217,33 @@ 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)))
}
// 父级节点有发生更新
if updateMenuCommand.ParentId != menu.ParentId && (updateMenuCommand.ParentId != 0 && menu.ParentId != 0) {
var oldParentFullPath, newParentFullPath = menu.GetFullPath(), menu.GetFullPath()
var oldParentPath = menu.ParentPath
if pMenu, err := menuRepository.FindOne(map[string]interface{}{"menuId": updateMenuCommand.ParentId}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
newParentFullPath = pMenu.GetParentPath()
menu.ParentPath = newParentFullPath
}
// 父级目录不一致时,联动更新其他的子节点的父级目录
if oldParentFullPath != newParentFullPath {
if _, menus, err := menuRepository.Find(map[string]interface{}{"parentPath": oldParentFullPath}); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
for i := range menus {
if menus[i].ParentPath == oldParentPath {
continue
}
menus[i].UpdateParentPath(oldParentPath, newParentFullPath)
if _, err := menuRepository.Save(menus[i]); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
}
}
}
}
if err := menu.Update(tool_funs.SimpleStructToMap(updateMenuCommand)); err != nil {
return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
}
... ...
package domain
import (
"fmt"
"strconv"
"strings"
)
var PathSegment = ","
// 系统菜单
type Menu struct {
// 菜单编号
... ... @@ -22,7 +30,7 @@ type Menu struct {
Remark string `json:"remark"`
// 菜单类别 (web:1、app:2)
Category string `json:"category"`
// 父级节点路径("0,11,12,")
// 路径节点路径("0,11,12,")
ParentPath string `json:"parentPath"`
// 菜单是否公开状态,[0:隐藏],[1:显示],默认显示
IsPublish int `json:"isPublish"`
... ... @@ -45,9 +53,6 @@ func (menu *Menu) Identify() interface{} {
}
func (menu *Menu) Update(data map[string]interface{}) error {
if menuId, ok := data["menuId"]; ok {
menu.MenuId = menuId.(int64)
}
if parentId, ok := data["parentId"]; ok {
menu.ParentId = parentId.(int64)
}
... ... @@ -72,12 +77,12 @@ func (menu *Menu) Update(data map[string]interface{}) error {
if desc, ok := data["desc"]; ok {
menu.Remark = desc.(string)
}
if category, ok := data["category"]; ok {
menu.Category = category.(string)
}
if parentPath, ok := data["parentPath"]; ok {
menu.ParentPath = parentPath.(string)
}
//if category, ok := data["category"]; ok {
// menu.Category = category.(string)
//}
//if fullPath, ok := data["fullPath"]; ok {
// menu.ParentPath = parentPath.(string)
//}
if isPublish, ok := data["isPublish"]; ok {
menu.IsPublish = isPublish.(int)
}
... ... @@ -86,3 +91,40 @@ func (menu *Menu) Update(data map[string]interface{}) error {
}
return nil
}
// GetParentPath 获取菜单路径
func (menu *Menu) GetParentPath() string {
if menu.ParentId == 0 {
return ""
}
if len(menu.ParentPath) > 0 {
return fmt.Sprintf("%v%v%v", menu.ParentPath, PathSegment, menu.MenuId)
}
return fmt.Sprintf("%v", menu.MenuId)
}
// GetFullPath 获取菜单全路径
func (menu *Menu) GetFullPath() string {
if menu.ParentId == 0 {
return ""
}
if len(menu.ParentPath) > 0 {
return fmt.Sprintf("%v%v%v", menu.ParentPath, PathSegment, menu.MenuId)
}
return fmt.Sprintf("%v", menu.MenuId)
}
// GetCategory 获取菜单类别 1.web 2.app
func (menu *Menu) GetCategory() string {
if menu.Category == "" {
return strconv.Itoa(int(menu.MenuId))
}
return menu.Category
}
func (menu *Menu) UpdateParentPath(old, new string) {
if !strings.Contains(menu.ParentPath, old) {
return
}
menu.ParentPath = strings.Replace(menu.ParentPath, old, new, 1)
}
... ...
... ... @@ -103,7 +103,6 @@ func (repository *MenuRepository) Save(menu *domain.Menu) (*domain.Menu, error)
&menu.IsSystem,
),
fmt.Sprintf("UPDATE base.menu SET %s WHERE menu_id=? RETURNING %s", updateFieldsSnippet, returningFieldsSnippet),
menu.MenuId,
menu.ParentId,
menu.MenuName,
menu.Code,
... ... @@ -136,7 +135,9 @@ func (repository *MenuRepository) FindOne(queryOptions map[string]interface{}) (
tx := repository.transactionContext.PgTx
menuModel := new(models.Menu)
query := sqlbuilder.BuildQuery(tx.Model(menuModel), queryOptions)
query.SetWhereByQueryOption("menu.menu_id = ?", "menuId")
query.SetWhereByQueryOption("menu_id = ?", "menuId")
query.SetWhereByQueryOption("parent_id = ?", "parentId")
query.SetWhereByQueryOption("code = ?", "code")
if err := query.First(); err != nil {
if err.Error() == "pg: no rows in result set" {
return nil, fmt.Errorf("没有此资源")
... ... @@ -155,8 +156,15 @@ func (repository *MenuRepository) Find(queryOptions map[string]interface{}) (int
var menuModels []*models.Menu
menus := make([]*domain.Menu, 0)
query := sqlbuilder.BuildQuery(tx.Model(&menuModels), queryOptions)
query.SetWhereByQueryOption("category = ?", "category")
if v, ok := queryOptions["parentPath"]; ok {
query.Where(fmt.Sprintf("parent_path like '%v%%'", v))
}
if v, ok := queryOptions["menuName"]; ok {
query.Where(fmt.Sprintf("menu_name like '%%%v%%'", v))
}
query.SetOffsetAndLimit(20)
query.SetOrderDirect("menu_id", "DESC")
query.SetOrderDirect("menu_id", "asc")
if count, err := query.SelectAndCount(); err != nil {
return 0, menus, err
} else {
... ...
... ... @@ -55,6 +55,9 @@ func (controller *MenuController) ListMenu() {
listMenuQuery.Offset = offset
limit, _ := controller.GetInt("limit")
listMenuQuery.Limit = limit
listMenuQuery.MenuCategory = controller.GetString("menuCategory")
listMenuQuery.MenuParentId, _ = controller.GetInt64("parentId", 0)
listMenuQuery.MenuName = controller.GetString("menuName")
data, err := menuService.ListMenu(listMenuQuery)
controller.Response(data, err)
}
... ...
... ... @@ -11,13 +11,12 @@ import (
)
var _ = Describe("返回菜单服务", func() {
return
var menuId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&menuId),
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, desc, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
"testMenuId", "testParentId", "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", "testSort", "testDesc", "testCategory", "testParentPath", "testIsPublish", "testIsSystem")
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, remark, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
1, 0, "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", 1, "testDesc", "testCategory", "testParentPath", 1, 1)
Expect(err).NotTo(HaveOccurred())
})
Describe("根据menuId参数返回系统菜单", func() {
... ... @@ -25,7 +24,7 @@ var _ = Describe("返回菜单服务", func() {
It("返回系统菜单数据", func() {
return
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.GET("/menus/{Id}").
httpExpect.GET("/menus/1").
Expect().
Status(http.StatusOK).
JSON().
... ...
... ... @@ -11,13 +11,12 @@ import (
)
var _ = Describe("返回菜单服务列表", func() {
return
var menuId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&menuId),
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, desc, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
"testMenuId", "testParentId", "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", "testSort", "testDesc", "testCategory", "testParentPath", "testIsPublish", "testIsSystem")
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, remark, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
1, 0, "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", 1, "testDesc", "testCategory", "testfullPath", 1, 1)
Expect(err).NotTo(HaveOccurred())
})
Describe("根据参数返回系统菜单列表", func() {
... ... @@ -26,8 +25,8 @@ var _ = Describe("返回菜单服务列表", func() {
return
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.GET("/menus/").
WithQuery("offset", "int").
WithQuery("limit", "int").
WithQuery("offset", 0).
WithQuery("limit", 20).
Expect().
Status(http.StatusOK).
JSON().
... ...
... ... @@ -11,13 +11,12 @@ import (
)
var _ = Describe("移除菜单服务", func() {
return
var menuId int64
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&menuId),
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, desc, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
"testMenuId", "testParentId", "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", "testSort", "testDesc", "testCategory", "testParentPath", "testIsPublish", "testIsSystem")
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, remark, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
1, 0, "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", 1, "testDesc", "testCategory", "testfullPath", 1, 1)
Expect(err).NotTo(HaveOccurred())
})
Describe("根据参数移除菜单服务", func() {
... ... @@ -25,7 +24,7 @@ var _ = Describe("移除菜单服务", func() {
It("返回被移除系统菜单的数据", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
httpExpect.DELETE("/menus/{Id}").
httpExpect.DELETE("/menus/1").
Expect().
Status(http.StatusOK).
JSON().
... ...
... ... @@ -12,12 +12,11 @@ import (
var _ = Describe("更新菜单服务", func() {
var menuId int64
return
BeforeEach(func() {
_, err := pG.DB.QueryOne(
pg.Scan(&menuId),
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, desc, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
"testMenuId", "testParentId", "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", "testSort", "testDesc", "testCategory", "testParentPath", "testIsPublish", "testIsSystem")
"INSERT INTO base.menu (menu_id, parent_id, menu_name, code, access_code, menu_type, icon, sort, remark, category, parent_path, is_publish, is_system) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING menu_id",
1, 0, "testMenuName", "testCode", "testAccessCode", "testMenuType", "testIcon", 1, "testDesc", "testCategory", "testfullPath", 1, 1)
Expect(err).NotTo(HaveOccurred())
})
Describe("提交数据更新菜单服务", func() {
... ... @@ -26,17 +25,16 @@ var _ = Describe("更新菜单服务", func() {
httpExpect := httpexpect.New(GinkgoT(), server.URL)
body := map[string]interface{}{
"menuId": "int64",
"menuName": "string",
"code": "string",
"menuName": "string11",
"code": "string22",
"accessCode": "string",
"menuType": "string",
"menuType": "cate",
"icon": "string",
"sort": "int",
"sort": 1,
"desc": "string",
"isPublish": "int",
"isPublish": 0,
}
httpExpect.PUT("/menus/{Id}").
httpExpect.PUT("/menus/1").
WithJSON(body).
Expect().
Status(http.StatusOK).
... ...