瀏覽代碼

Merge branch 'debug' of http://8.136.199.33:3000/hongze/hz_crm_api into debug

xingzai 1 年之前
父節點
當前提交
b14e0579fb

+ 479 - 38
controllers/eta_business/eta_business_menu.go

@@ -2,10 +2,15 @@ package eta_business
 
 import (
 	"encoding/json"
+	"fmt"
 	"hongze/hz_crm_api/controllers"
 	"hongze/hz_crm_api/models"
 	"hongze/hz_crm_api/models/eta_business"
 	etaBusinessService "hongze/hz_crm_api/services/eta_business"
+	"hongze/hz_crm_api/utils"
+	"html/template"
+	"strings"
+	"time"
 )
 
 // EtaBusinessMenuController ETA商家菜单
@@ -16,7 +21,8 @@ type EtaBusinessMenuController struct {
 // List
 // @Title 商家菜单列表
 // @Description 商家菜单列表
-// @Param   BusinessId	query	int	false	"商家ID"
+// @Param   BusinessId	query	int		false	"商家ID"
+// @Param   Keyword		query	string	false	"关键词: 菜单名称"
 // @Success 200 Ret=200 获取成功
 // @router /menu/list [get]
 func (this *EtaBusinessMenuController) List() {
@@ -55,54 +61,78 @@ func (this *EtaBusinessMenuController) List() {
 		return
 	}
 
+	menuCond := ``
+	menuPars := make([]interface{}, 0)
 	// 商家勾选的权限
-	businessId, _ := this.GetInt("EtaBusinessId", 0)
-	if businessId > 0 {
-		relateOb := new(eta_business.EtaBusinessMenuRelate)
-		cond := ` AND eta_business_id = ?`
-		pars := make([]interface{}, 0)
-		pars = append(pars, businessId)
-		relates, e := relateOb.GetItemsByCondition(cond, pars, []string{}, "")
+	{
+		businessId, _ := this.GetInt("EtaBusinessId", 0)
+		if businessId > 0 {
+			relateOb := new(eta_business.EtaBusinessMenuRelate)
+			cond := ` AND eta_business_id = ?`
+			pars := make([]interface{}, 0)
+			pars = append(pars, businessId)
+			relates, e := relateOb.GetItemsByCondition(cond, pars, []string{}, "")
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取商家菜单关联列表失败, Err: " + e.Error()
+				return
+			}
+			for _, r := range relates {
+				if r.Type == 1 {
+					resp.HalfChoiceList = append(resp.HalfChoiceList, r.MenuId)
+					continue
+				}
+				resp.ChoiceList = append(resp.ChoiceList, r.MenuId)
+			}
+			menuCond += ` AND hidden = 0`
+		}
+	}
+
+	list := make([]*eta_business.EtaBusinessMenu, 0)
+	order := `sort ASC, create_time DESC, menu_id DESC`
+
+	// 关键词
+	keyword := this.GetString("Keyword")
+	keyword = strings.TrimSpace(keyword)
+	if keyword != "" {
+		keyword = template.HTMLEscapeString(keyword)
+		kw := fmt.Sprint("%", keyword, "%")
+		menus, e := eta_business.GetMenuItemsByKeyword(kw, []string{}, order)
 		if e != nil {
 			br.Msg = "获取失败"
-			br.ErrMsg = "获取商家菜单关联列表失败, Err: " + e.Error()
+			br.ErrMsg = "获取商家菜单列表失败, Err: " + e.Error()
 			return
 		}
-		for _, r := range relates {
-			if r.Type == 1 {
-				resp.HalfChoiceList = append(resp.HalfChoiceList, r.MenuId)
-				continue
-			}
-			resp.ChoiceList = append(resp.ChoiceList, r.MenuId)
-		}
+		list = menus
 	}
 
-	menuOb := new(eta_business.EtaBusinessMenu)
-	order := `sort ASC, create_time DESC, menu_id DESC`
-	list, e := menuOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, order)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取商家菜单列表失败, Err: " + e.Error()
-		return
+	// 普通查询
+	if keyword == "" {
+		menuOb := new(eta_business.EtaBusinessMenu)
+		menus, e := menuOb.GetItemsByCondition(menuCond, menuPars, []string{}, order)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取商家菜单列表失败, Err: " + e.Error()
+			return
+		}
+		list = menus
 	}
 
 	items := make([]*eta_business.EtaBusinessMenuItem, 0)
 	for _, v := range list {
 		t := &eta_business.EtaBusinessMenuItem{
-			MenuId:       v.MenuId,
-			ParentId:     v.ParentId,
-			Name:         v.Name,
-			Sort:         v.Sort,
-			Path:         v.Path,
-			PathName:     v.PathName,
-			IconPath:     v.IconPath,
-			Component:    v.Component,
-			Hidden:       v.Hidden,
-			HiddenLayout: v.HiddenLayout,
-			Level:        v.Level,
-			MenuType:     v.MenuType,
-			ButtonCode:   v.ButtonCode,
-			Children:     make([]*eta_business.EtaBusinessMenuItem, 0),
+			MenuId:     v.MenuId,
+			ParentId:   v.ParentId,
+			Name:       v.Name,
+			Sort:       v.Sort,
+			Path:       v.Path,
+			IconPath:   v.IconPath,
+			Component:  v.Component,
+			Hidden:     v.Hidden,
+			MenuType:   v.MenuType,
+			ButtonCode: v.ButtonCode,
+			CreateTime: v.CreateTime.Format(utils.FormatDateTime),
+			Children:   make([]*eta_business.EtaBusinessMenuItem, 0),
 		}
 		items = append(items, t)
 	}
@@ -189,7 +219,418 @@ func (this *EtaBusinessMenuController) SaveRelate() {
 		return
 	}
 
-	// TODO:后续需要生成SQL脚本文件
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Add
+// @Title 新增菜单
+// @Description 新增菜单
+// @Param	request	body eta_business.EtaBusinessMenuAddReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /menu/add [post]
+func (this *EtaBusinessMenuController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	// 操作权限校验
+	ok, e := etaBusinessService.CheckEtaBusinessOperateAuth(sysUser.RoleTypeCode)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "操作权限校验失败, ErrMsg: " + e.Error()
+		return
+	}
+	if !ok {
+		br.Msg = "无权操作"
+		return
+	}
+
+	// 参数校验
+	var req eta_business.EtaBusinessMenuAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	req.Name = strings.TrimSpace(req.Name)
+	if req.Name == "" {
+		br.Msg = "请输入名称"
+		return
+	}
+	if req.MenuType == 0 {
+		req.Path = strings.TrimSpace(req.Path)
+		if req.Path == "" {
+			br.Msg = "请输入路由地址"
+			return
+		}
+		req.Component = strings.TrimSpace(req.Component)
+		if req.Component == "" {
+			br.Msg = "请输入组件路径"
+			return
+		}
+	} else {
+		req.ButtonCode = strings.TrimSpace(req.ButtonCode)
+		if req.ButtonCode == "" {
+			br.Msg = "请输入按钮/字段ID"
+			return
+		}
+	}
+
+	// 重名校验
+	{
+		ob := new(eta_business.EtaBusinessMenu)
+		cond := ` AND parent_id = ? AND name = ?`
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.ParentId, req.Name)
+		exist, e := ob.GetItemByCondition(cond, pars)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取同名菜单失败, Err: " + e.Error()
+			return
+		}
+		if exist != nil {
+			br.Msg = "名称已存在"
+			return
+		}
+	}
+
+	// 新增
+	menuOb := new(eta_business.EtaBusinessMenu)
+	menuOb.ParentId = req.ParentId
+	menuOb.Name = req.Name
+	menuOb.Sort = req.Sort
+	menuOb.Path = req.Path
+	menuOb.IconPath = req.IconPath
+	menuOb.Component = req.Component
+	menuOb.Hidden = req.Hidden
+	menuOb.MenuType = req.MenuType
+	menuOb.ButtonCode = req.ButtonCode
+	menuOb.CreateTime = time.Now().Local()
+	menuOb.ModifyTime = time.Now().Local()
+	// TODO:多级菜单
+	if menuOb.ParentId > 0 {
+		menuOb.LevelPath = menuOb.Component
+	}
+	if e := menuOb.Create(); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "新增菜单失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Edit
+// @Title 编辑菜单
+// @Description 编辑菜单
+// @Param	request	body eta_business.EtaBusinessMenuEditReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /menu/edit [post]
+func (this *EtaBusinessMenuController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	// 操作权限校验
+	ok, e := etaBusinessService.CheckEtaBusinessOperateAuth(sysUser.RoleTypeCode)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "操作权限校验失败, ErrMsg: " + e.Error()
+		return
+	}
+	if !ok {
+		br.Msg = "无权操作"
+		return
+	}
+
+	// 参数校验
+	var req eta_business.EtaBusinessMenuEditReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if req.MenuId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数有误, MenuId"
+		return
+	}
+	req.Name = strings.TrimSpace(req.Name)
+	if req.Name == "" {
+		br.Msg = "请输入名称"
+		return
+	}
+	if req.MenuType == 0 {
+		req.Path = strings.TrimSpace(req.Path)
+		if req.Path == "" {
+			br.Msg = "请输入路由地址"
+			return
+		}
+		req.Component = strings.TrimSpace(req.Component)
+		if req.Component == "" {
+			br.Msg = "请输入组件路径"
+			return
+		}
+	} else {
+		req.ButtonCode = strings.TrimSpace(req.ButtonCode)
+		if req.ButtonCode == "" {
+			br.Msg = "请输入按钮/字段ID"
+			return
+		}
+	}
+
+	menuOb := new(eta_business.EtaBusinessMenu)
+	item, e := menuOb.GetItemById(req.MenuId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "菜单不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取菜单失败, Err: " + e.Error()
+		return
+	}
+
+	// 重名校验
+	{
+		ob := new(eta_business.EtaBusinessMenu)
+		cond := ` AND parent_id = ? AND name = ?`
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.ParentId, req.Name)
+		exist, e := ob.GetItemByCondition(cond, pars)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取同名菜单失败, Err: " + e.Error()
+			return
+		}
+		if exist != nil && exist.MenuId != item.MenuId {
+			br.Msg = "名称已存在"
+			return
+		}
+	}
+
+	// 更新
+	item.Name = req.Name
+	item.Sort = req.Sort
+	item.Path = req.Path
+	item.IconPath = req.IconPath
+	item.Component = req.Component
+	item.Hidden = req.Hidden
+	item.ButtonCode = req.ButtonCode
+	item.ModifyTime = time.Now().Local()
+	// TODO:多级菜单
+	cols := make([]string, 0)
+	cols = append(cols, "Name", "Sort", "Path", "IconPath", "Component", "Hidden", "ButtonCode", "ModifyTime")
+	if item.ParentId > 0 {
+		item.LevelPath = item.Component
+		cols = append(cols, "LevelPath")
+	}
+	if e := item.Update(cols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新菜单失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Remove
+// @Title 删除菜单
+// @Description 删除菜单
+// @Param	request	body eta_business.EtaBusinessMenuRemoveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /menu/remove [post]
+func (this *EtaBusinessMenuController) Remove() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	// 操作权限校验
+	ok, e := etaBusinessService.CheckEtaBusinessOperateAuth(sysUser.RoleTypeCode)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "操作权限校验失败, ErrMsg: " + e.Error()
+		return
+	}
+	if !ok {
+		br.Msg = "无权操作"
+		return
+	}
+
+	// 参数校验
+	var req eta_business.EtaBusinessMenuRemoveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if req.MenuId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数有误, MenuId"
+		return
+	}
+
+	menuOb := new(eta_business.EtaBusinessMenu)
+	_, e = menuOb.GetItemById(req.MenuId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "菜单不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取菜单失败, Err: " + e.Error()
+		return
+	}
+
+	// 获取所有菜单列表, 筛选出该菜单及子菜单
+	menus, e := menuOb.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取菜单列表失败, Err: " + e.Error()
+		return
+	}
+	menuIds := etaBusinessService.GetMenuChildrenIdsRecursive(menus, req.MenuId)
+	menuIds = append(menuIds, req.MenuId)
+
+	// 删除菜单
+	if e = menuOb.MultiDel(menuIds); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "删除菜单及子菜单失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// IconList
+// @Title 图标列表
+// @Description 图标列表
+// @Success 200 Ret=200 操作成功
+// @router /menu/icon/list [get]
+func (this *EtaBusinessMenuController) IconList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	iconOb := new(eta_business.EtaBusinessMenuIcon)
+	icons, e := iconOb.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取菜单列表失败, Err: " + e.Error()
+		return
+	}
+	list := make([]*eta_business.EtaBusinessMenuIconItem, 0)
+	for _, v := range icons {
+		list = append(list, &eta_business.EtaBusinessMenuIconItem{
+			IconId:   v.IconId,
+			IconPath: v.IconPath,
+		})
+	}
+
+	br.Data = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// IconAdd
+// @Title 新增图标
+// @Description 新增图标
+// @Success 200 Ret=200 操作成功
+// @router /menu/icon/add [post]
+func (this *EtaBusinessMenuController) IconAdd() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req eta_business.EtaBusinessMenuIconAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	req.IconPath = strings.TrimSpace(req.IconPath)
+	if req.IconPath == "" {
+		br.Msg = "请上传图片"
+		return
+	}
+
+	iconOb := new(eta_business.EtaBusinessMenuIcon)
+	iconOb.IconPath = req.IconPath
+	iconOb.CreateTime = time.Now().Local()
+	if e := iconOb.Create(); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "新增菜单icon失败, Err: " + e.Error()
+		return
+	}
 
 	br.Ret = 200
 	br.Success = true

+ 1 - 1
controllers/sys_role.go

@@ -97,7 +97,7 @@ func (this *SysRoleController) Edit() {
 		return
 	}
 	if req.RoleName == "" {
-		br.Msg = "分组名称不能为空"
+		br.Msg = "角色名称不能为空"
 		return
 	}
 	item, err := system.GetSysRoleByName(req.RoleName)

+ 1 - 0
models/db.go

@@ -667,6 +667,7 @@ func initEtaBusiness() {
 		new(eta_business.EtaBusinessOperationRecord), // ETA操作记录表
 		new(eta_business.EtaBusinessMenu),            // ETA商家菜单表
 		new(eta_business.EtaBusinessMenuRelate),      // ETA商家菜单关联表
+		new(eta_business.EtaBusinessMenuIcon),        // ETA商家菜单icon表
 	)
 }
 

+ 83 - 20
models/eta_business/eta_business_menu.go

@@ -3,30 +3,27 @@ package eta_business
 import (
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"hongze/hz_crm_api/utils"
 	"strings"
 	"time"
 )
 
 // EtaBusinessMenu ETA商家基础菜单表
 type EtaBusinessMenu struct {
-	MenuId       int       `orm:"column(menu_id);pk"`
-	ParentId     int       `description:"父级菜单ID"`
-	Name         string    `description:"菜单名称或者按钮名称"`
-	RootId       int       `description:"顶层菜单ID"`
-	Sort         string    `description:"排序"`
-	Path         string    `description:"路由地址"`
-	PathName     string    `description:"路由名称"`
-	IconPath     string    `description:"菜单图标地址"`
-	Component    int       `description:"组件路径"`
-	Hidden       int       `description:"是否隐藏:1-隐藏 0-显示"`
-	HiddenLayout int       `description:"是否隐藏layout:1-隐藏 0-显示"`
-	Level        int       `description:"菜单等级:1-2-3"`
-	IsLevel      int       `description:"是否为多级菜单:1,只有一级;2,有多级"`
-	LevelPath    string    `description:"兼容以前menu表的字段"`
-	MenuType     int       `description:"菜单类型: 0-菜单; 1-按钮; 2-字段(需要特殊处理)"`
-	ButtonCode   string    `description:"按钮/菜单唯一标识"`
-	CreateTime   time.Time `description:"创建时间"`
-	ModifyTime   time.Time `description:"更新时间"`
+	MenuId     int       `orm:"column(menu_id);pk"`
+	ParentId   int       `description:"父级菜单ID"`
+	Name       string    `description:"菜单名称或者按钮名称"`
+	Sort       int       `description:"排序"`
+	Path       string    `description:"路由地址"`
+	IconPath   string    `description:"菜单图标地址"`
+	Component  string    `description:"组件路径"`
+	Hidden     int       `description:"是否隐藏:1-隐藏 0-显示"`
+	IsLevel    int       `description:"是否为多级菜单:1,只有一级;2,有多级"`
+	LevelPath  string    `description:"兼容以前menu表的字段"`
+	MenuType   int       `description:"菜单类型: 0-菜单; 1-按钮; 2-字段(需要特殊处理)"`
+	ButtonCode string    `description:"按钮唯一标识"`
+	CreateTime time.Time `description:"创建时间"`
+	ModifyTime time.Time `description:"更新时间"`
 }
 
 func (m *EtaBusinessMenu) TableName() string {
@@ -69,6 +66,16 @@ func (m *EtaBusinessMenu) Del() (err error) {
 	return
 }
 
+func (m *EtaBusinessMenu) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
 func (m *EtaBusinessMenu) GetItemById(id int) (item *EtaBusinessMenu, err error) {
 	o := orm.NewOrm()
 	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
@@ -120,6 +127,37 @@ func (m *EtaBusinessMenu) GetPageItemsByCondition(condition string, pars []inter
 	return
 }
 
+// GetMenuItemsByKeyword 关键词获取菜单
+func GetMenuItemsByKeyword(keyword string, fieldArr []string, orderRule string) (items []*EtaBusinessMenu, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT
+				%s
+			FROM
+				(
+					SELECT * FROM eta_business_menu WHERE parent_id = 0 AND name LIKE ?
+					UNION
+					SELECT * FROM eta_business_menu WHERE menu_id IN (
+						SELECT
+							parent_id
+						FROM
+							eta_business_menu
+						WHERE
+							parent_id > 0 AND name LIKE ?
+					)
+				) AS t %s`
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql = fmt.Sprintf(sql, fields, order)
+	_, err = o.Raw(sql, keyword, keyword).QueryRows(&items)
+	return
+}
+
 // EtaBusinessMenuListResp ETA商家菜单列表响应体
 type EtaBusinessMenuListResp struct {
 	ChoiceList     []int                  `description:"已选菜单"`
@@ -133,15 +171,40 @@ type EtaBusinessMenuItem struct {
 	ParentId     int                    `description:"父级菜单ID"`
 	Name         string                 `description:"菜单名称或者按钮名称"`
 	RootId       int                    `description:"顶层菜单ID"`
-	Sort         string                 `description:"排序"`
+	Sort         int                    `description:"排序"`
 	Path         string                 `description:"路由地址"`
 	PathName     string                 `description:"路由名称"`
 	IconPath     string                 `description:"菜单图标地址"`
-	Component    int                    `description:"组件路径"`
+	Component    string                 `description:"组件路径"`
 	Hidden       int                    `description:"是否隐藏:1-隐藏 0-显示"`
 	HiddenLayout int                    `description:"是否隐藏layout:1-隐藏 0-显示"`
 	Level        int                    `description:"菜单等级:1-2-3"`
 	MenuType     int                    `description:"菜单类型: 0-菜单; 1-按钮; 2-字段(需要特殊处理)"`
 	ButtonCode   string                 `description:"按钮/菜单唯一标识"`
+	CreateTime   string                 `description:"创建时间"`
 	Children     []*EtaBusinessMenuItem `description:"子菜单"`
 }
+
+// EtaBusinessMenuAddReq 新增菜单请求体
+type EtaBusinessMenuAddReq struct {
+	ParentId   int    `description:"父级菜单ID"`
+	Name       string `description:"菜单/按钮名称"`
+	Sort       int    `description:"排序"`
+	Path       string `description:"路由地址"`
+	IconPath   string `description:"图标地址"`
+	Component  string `description:"组件路径"`
+	Hidden     int    `description:"是否隐藏:1-隐藏 0-显示"`
+	MenuType   int    `description:"菜单类型:0-菜单; 1-按钮; 2-字段"`
+	ButtonCode string `description:"按钮唯一标识"`
+}
+
+// EtaBusinessMenuEditReq 编辑菜单请求体
+type EtaBusinessMenuEditReq struct {
+	MenuId int
+	EtaBusinessMenuAddReq
+}
+
+// EtaBusinessMenuRemoveReq 删除菜单请求体
+type EtaBusinessMenuRemoveReq struct {
+	MenuId int
+}

+ 117 - 0
models/eta_business/eta_business_menu_icon.go

@@ -0,0 +1,117 @@
+package eta_business
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// EtaBusinessMenuIcon 菜单icon表
+type EtaBusinessMenuIcon struct {
+	IconId     int       `orm:"column(icon_id);pk"`
+	IconPath   string    `description:"icon地址"`
+	CreateTime time.Time `description:"创建时间"`
+}
+
+func (m *EtaBusinessMenuIcon) TableName() string {
+	return "eta_business_menu_icon"
+}
+
+func (m *EtaBusinessMenuIcon) PrimaryId() string {
+	return "icon_id"
+}
+
+func (m *EtaBusinessMenuIcon) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.IconId = int(id)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) CreateMulti(items []*EtaBusinessMenuIcon) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) Del() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.IconId).Exec()
+	return
+}
+
+func (m *EtaBusinessMenuIcon) GetItemById(id int) (item *EtaBusinessMenuIcon, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) GetItemByCondition(condition string, pars []interface{}) (item *EtaBusinessMenuIcon, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s LIMIT 1`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*EtaBusinessMenuIcon, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC, icon_id ASC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *EtaBusinessMenuIcon) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*EtaBusinessMenuIcon, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// EtaBusinessMenuIconItem 菜单icon
+type EtaBusinessMenuIconItem struct {
+	IconId   int
+	IconPath string `description:"icon地址"`
+}
+
+// EtaBusinessMenuIconAddReq 新增icon请求体
+type EtaBusinessMenuIconAddReq struct {
+	IconPath string `description:"icon地址"`
+}

+ 45 - 0
routers/commentsRouter.go

@@ -6577,6 +6577,42 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/menu/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/menu/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
+        beego.ControllerComments{
+            Method: "IconAdd",
+            Router: `/menu/icon/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
+        beego.ControllerComments{
+            Method: "IconList",
+            Router: `/menu/icon/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
         beego.ControllerComments{
             Method: "List",
@@ -6595,6 +6631,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/eta_business:EtaBusinessMenuController"],
+        beego.ControllerComments{
+            Method: "Remove",
+            Router: `/menu/remove`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/help_doc:HelpDocClassifyController"] = append(beego.GlobalControllerRouter["hongze/hz_crm_api/controllers/help_doc:HelpDocClassifyController"],
         beego.ControllerComments{
             Method: "AddClassify",

+ 16 - 1
services/eta_business/eta_business_menu.go

@@ -1,6 +1,8 @@
 package eta_business
 
-import "hongze/hz_crm_api/models/eta_business"
+import (
+	"hongze/hz_crm_api/models/eta_business"
+)
 
 // GetMenuTreeRecursive 递归菜单树
 func GetMenuTreeRecursive(list []*eta_business.EtaBusinessMenuItem, parentId int) []*eta_business.EtaBusinessMenuItem {
@@ -13,3 +15,16 @@ func GetMenuTreeRecursive(list []*eta_business.EtaBusinessMenuItem, parentId int
 	}
 	return res
 }
+
+// GetMenuChildrenIdsRecursive 遍历子菜单IDs
+func GetMenuChildrenIdsRecursive(list []*eta_business.EtaBusinessMenu, parentId int) []int {
+	res := make([]int, 0)
+	for _, v := range list {
+		if v.ParentId == parentId {
+			ids := GetMenuChildrenIdsRecursive(list, v.MenuId)
+			res = append(res, v.MenuId)
+			res = append(res, ids...)
+		}
+	}
+	return res
+}