From fb816707768cc06660d3695ee9fca71e91d77786 Mon Sep 17 00:00:00 2001 From: wol <1293433164@qq.com> Date: Mon, 25 Aug 2025 00:09:18 +0800 Subject: [PATCH] menu --- .../menu/controller/SysMenuController.java | 73 +++++++++- .../system/menu/mapper/SysMenuMapper.java | 51 +++++++ .../system/menu/mapper/xml/SysMenuMapper.xml | 6 + .../system/menu/pojo/dto/AddMenuCommand.java | 36 +++++ .../system/menu/pojo/dto/ExtraIconDTO.java | 16 +++ .../system/menu/pojo/dto/MenuDTO.java | 77 +++++++++++ .../system/menu/pojo/dto/MenuDetailDTO.java | 30 ++++ .../system/menu/pojo/dto/MenuQuery.java | 15 ++ .../system/menu/pojo/dto/MetaDTO.java | 61 ++++++++ .../system/menu/pojo/dto/TransitionDTO.java | 19 +++ .../menu/pojo/dto/UpdateMenuCommand.java | 17 +++ .../system/menu/pojo/entity/SysMenu.java | 77 +++++++++++ .../system/menu/service/ISysMenuService.java | 21 +++ .../menu/service/impl/SysMenuServiceImpl.java | 130 ++++++++++++++++++ .../controller/pojo/entity/SysRoleMenu.java | 46 +++++++ 15 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/SysMenuMapper.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/xml/SysMenuMapper.xml create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/AddMenuCommand.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/ExtraIconDTO.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDTO.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDetailDTO.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuQuery.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MetaDTO.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/TransitionDTO.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/UpdateMenuCommand.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/entity/SysMenu.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java create mode 100644 agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/role/controller/pojo/entity/SysRoleMenu.java diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/controller/SysMenuController.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/controller/SysMenuController.java index df86372..ca09a11 100644 --- a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/controller/SysMenuController.java +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/controller/SysMenuController.java @@ -1,9 +1,17 @@ package com.agileboot.system.menu.controller; +import cn.hutool.core.lang.tree.Tree; +import com.agileboot.common.core.core.R; +import com.agileboot.common.satoken.pojo.LoginUser; +import com.agileboot.common.satoken.utils.LoginHelper; +import com.agileboot.system.menu.pojo.dto.*; +import com.agileboot.system.menu.service.ISysMenuService; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; /** * 菜单信息 @@ -14,4 +22,65 @@ import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor public class SysMenuController { + private final ISysMenuService sysMenuService; + + /** + * 获取菜单列表 + */ + @GetMapping + public R> menuList(MenuQuery menuQuery) { + List menuList = sysMenuService.getMenuList(menuQuery); + return R.ok(menuList); + } + + /** + * 根据菜单编号获取详细信息 + */ + @GetMapping(value = "/{menuId}") + public R menuInfo(@PathVariable("menuId") @NotNull Long menuId) { + MenuDetailDTO menu = sysMenuService.getMenuInfo(menuId); + return R.ok(menu); + } + + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/dropdown") + public R>> dropdownList() { + LoginUser loginUser = LoginHelper.getLoginUser(); + List> dropdownList = sysMenuService.getDropdownList(loginUser); + return R.ok(dropdownList); + } + + /** + * 新增菜单 + * 需支持一级菜单以及 多级菜单 子菜单为一个 或者 多个的情况 + * 隐藏菜单不显示 以及rank排序 + * 内链 和 外链 + */ + @PostMapping + public R add(@RequestBody AddMenuCommand addCommand) { + sysMenuService.addMenu(addCommand); + return R.ok(); + } + + /** + * 修改菜单 + */ + @PostMapping("/{menuId}") + public R edit(@PathVariable("menuId") Long menuId, @RequestBody UpdateMenuCommand updateCommand) { + updateCommand.setMenuId(menuId); + sysMenuService.updateMenu(updateCommand); + return R.ok(); + } + + /** + * 删除菜单 + */ + @PostMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + sysMenuService.remove(menuId); + return R.ok(); + } + } diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/SysMenuMapper.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/SysMenuMapper.java new file mode 100644 index 0000000..6a1a44f --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/SysMenuMapper.java @@ -0,0 +1,51 @@ +package com.agileboot.system.menu.mapper; + +import com.agileboot.system.menu.pojo.entity.SysMenu; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 菜单权限表 Mapper 接口 + *

+ * + * @author valarchie + * @since 2022-06-16 + */ +public interface SysMenuMapper extends BaseMapper { + + /** + * 根据用户查询出所有菜单 + * + * @param userId 用户id + * @return 菜单列表 + */ + @Select("SELECT DISTINCT m.* " + + "FROM sys_menu m " + + " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id " + + " LEFT JOIN sys_user u ON rm.role_id = u.role_id " + + "WHERE u.user_id = #{userId} " + + " AND m.status = 1 " + + " AND m.deleted = 0 " + + "ORDER BY m.parent_id") + List selectMenuListByUserId(@Param("userId")Long userId); + + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Select("SELECT DISTINCT m.menu_id " + + "FROM sys_menu m " + + " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id " + + "WHERE rm.role_id = #{roleId} " + + " AND m.deleted = 0 " + + "GROUP BY m.menu_id ") + List selectMenuIdsByRoleId(@Param("roleId") Long roleId); + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/xml/SysMenuMapper.xml b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/xml/SysMenuMapper.xml new file mode 100644 index 0000000..39e591c --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/mapper/xml/SysMenuMapper.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/AddMenuCommand.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/AddMenuCommand.java new file mode 100644 index 0000000..a679a19 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/AddMenuCommand.java @@ -0,0 +1,36 @@ +package com.agileboot.system.menu.pojo.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + + +/** + * @author valarchie + */ +@Data +public class AddMenuCommand { + + private Long parentId; + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String menuName; + /** + * 路由名称 必须唯一 + */ + private String routerName; + + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + private Integer status; + private Integer menuType; + + private Boolean isButton; + + @Size(max = 100, message = "权限标识长度不能超过100个字符") + private String permission; + + private MetaDTO meta; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/ExtraIconDTO.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/ExtraIconDTO.java new file mode 100644 index 0000000..dd53928 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/ExtraIconDTO.java @@ -0,0 +1,16 @@ +package com.agileboot.system.menu.pojo.dto; + +import lombok.Data; + +/** + * @author valarchie + */ +@Data +public class ExtraIconDTO { + + // 是否是svg + private boolean svg; + // iconfont名称,目前只支持iconfont,后续拓展 + private String name; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDTO.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDTO.java new file mode 100644 index 0000000..c9f90da --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDTO.java @@ -0,0 +1,77 @@ +package com.agileboot.system.menu.pojo.dto; + +import cn.hutool.core.util.StrUtil; +import com.agileboot.common.core.enums.BasicEnumUtil; +import com.agileboot.common.core.enums.common.MenuTypeEnum; +import com.agileboot.common.core.enums.common.StatusEnum; +import com.agileboot.common.core.utils.jackson.JacksonUtil; +import com.agileboot.system.menu.pojo.entity.SysMenu; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author valarchie + */ +@Data +@NoArgsConstructor +public class MenuDTO { + + public MenuDTO(SysMenu entity) { + if (entity != null) { + this.id = entity.getMenuId(); + this.parentId = entity.getParentId(); + this.menuName = entity.getMenuName(); + this.routerName = entity.getRouterName(); + this.path = entity.getPath(); + this.status = entity.getStatus(); + this.isButton = entity.getIsButton(); + this.statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus()); + + if (!entity.getIsButton()) { + this.menuType = entity.getMenuType(); + this.menuTypeStr = BasicEnumUtil.getDescriptionByValue(MenuTypeEnum.class, entity.getMenuType()); + } else { + this.menuType = 0; + } + + if (StrUtil.isNotEmpty(entity.getMetaInfo()) && JacksonUtil.isJson(entity.getMetaInfo())) { + MetaDTO meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class); + this.rank = meta.getRank(); + this.icon = meta.getIcon(); + } + this.createTime = entity.getCreateTime(); + } + } + + // 设置成id和parentId 便于前端处理树级结构 + private Long id; + + private Long parentId; + + private String menuName; + + private String routerName; + + private String path; + + private Integer rank; + + private Integer menuType; + + private String menuTypeStr; + + private Boolean isButton; + + private Integer status; + + private String statusStr; + + private Date createTime; + + private String icon; + + + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDetailDTO.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDetailDTO.java new file mode 100644 index 0000000..df97257 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuDetailDTO.java @@ -0,0 +1,30 @@ +package com.agileboot.system.menu.pojo.dto; + +import cn.hutool.core.util.StrUtil; +import com.agileboot.common.core.utils.jackson.JacksonUtil; +import com.agileboot.system.menu.pojo.entity.SysMenu; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author valarchie + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class MenuDetailDTO extends MenuDTO { + + public MenuDetailDTO(SysMenu entity) { + super(entity); + if (entity == null) { + return; + } + if (StrUtil.isNotEmpty(entity.getMetaInfo()) && JacksonUtil.isJson(entity.getMetaInfo())) { + this.meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class); + } + this.permission = entity.getPermission(); + } + + private String permission; + private MetaDTO meta; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuQuery.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuQuery.java new file mode 100644 index 0000000..399d14d --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MenuQuery.java @@ -0,0 +1,15 @@ +package com.agileboot.system.menu.pojo.dto; + +import lombok.Data; + +/** + * @author valarchie + */ +@Data +public class MenuQuery { + // 直接交给前端筛选 +// private String menuName; +// private Boolean isVisible; +// private Integer status; + private Boolean isButton; +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MetaDTO.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MetaDTO.java new file mode 100644 index 0000000..f8b40be --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/MetaDTO.java @@ -0,0 +1,61 @@ +package com.agileboot.system.menu.pojo.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 路由显示信息 + * 必须加上@JsonInclude(Include.NON_NULL)的注解 否则传null值给Vue动态路由渲染时会出错 + * @author valarchie + */ +@Data +@NoArgsConstructor +@JsonInclude(Include.NON_NULL) +public class MetaDTO { + // 菜单名称(兼容国际化、非国际化,如果用国际化的写法就必须在根目录的locales文件夹下对应添加) + private String title; + // 菜单图标 + private String icon; + // 是否显示该菜单 + private Boolean showLink; + // 是否显示父级菜单 + private Boolean showParent; + // 页面级别权限设置 + private List roles; + // 按钮级别权限设置 + private List auths; + // 需要内嵌的iframe链接地址 + private String frameSrc; + /** + * 是否是内部页面 使用frameSrc来嵌入页面时,当isFrameSrcInternal=true的时候, 前端需要做特殊处理 + * 比如链接是 /druid/login.html + * 前端需要处理成 http://localhost:8080/druid/login.html + */ + private Boolean isFrameSrcInternal; + + /** + * 菜单排序,值越高排的越后(只针对顶级路由) + */ + private Integer rank; + + + // ========= 目前系统仅支持以上这些参数的设置 后续有需要的话开发者可自行设置的这些参数 =========== + + // 菜单名称右侧的额外图标 + private ExtraIconDTO extraIcon; + // 是否缓存该路由页面(开启后,会保存该页面的整体状态,刷新后会清空状态) + private Boolean keepAlive; + // 内嵌的iframe页面是否开启首次加载动画 + private Boolean frameLoading; + // 页面加载动画(两种模式,第一种直接采用vue内置的transitions动画,第二种是使用animate.css编写进、离场动画,平台更推荐使用第二种模式,已经内置了animate.css,直接写对应的动画名即可) + private TransitionDTO transition; + // 当前菜单名称或自定义信息禁止添加到标签页 + private Boolean hiddenTag; + // 显示在标签页的最大数量,需满足后面的条件:不显示在菜单中的路由并且是通过query或params传参模式打开的页面。在完整版全局搜dynamicLevel即可查看代码演示 + private Integer dynamicLevel; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/TransitionDTO.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/TransitionDTO.java new file mode 100644 index 0000000..ea69678 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/TransitionDTO.java @@ -0,0 +1,19 @@ +package com.agileboot.system.menu.pojo.dto; + +import lombok.Data; + +/** + * @author valarchie + */ +@Data +public class TransitionDTO { + + // 当前页面动画,这里是第一种模式,比如 name: "fade" 更具体看后面链接 + // https://cn.vuejs.org/api/built-in-components.html#transition + private String name; + // 当前页面进场动画,这里是第二种模式,比如 enterTransition: "animate__fadeInLeft" + private String enterTransition; + // 当前页面离场动画,这里是第二种模式,比如 leaveTransition: "animate__fadeOutRight" + private String leaveTransition; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/UpdateMenuCommand.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/UpdateMenuCommand.java new file mode 100644 index 0000000..4d30671 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/dto/UpdateMenuCommand.java @@ -0,0 +1,17 @@ +package com.agileboot.system.menu.pojo.dto; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author valarchie + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class UpdateMenuCommand extends AddMenuCommand { + + @NotNull + private Long menuId; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/entity/SysMenu.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/entity/SysMenu.java new file mode 100644 index 0000000..07d4809 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/pojo/entity/SysMenu.java @@ -0,0 +1,77 @@ +package com.agileboot.system.menu.pojo.entity; + +import com.agileboot.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; + +/** + *

+ * 菜单权限表 + *

+ * + * @author valarchie + * @since 2023-07-21 + */ +@Getter +@Setter +@TableName("sys_menu") +@ApiModel(value = "SysMenuEntity对象", description = "菜单权限表") +public class SysMenu extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + + @ApiModelProperty("菜单ID") + @TableId(value = "menu_id", type = IdType.AUTO) + private Long menuId; + + @ApiModelProperty("菜单名称") + @TableField("menu_name") + private String menuName; + + @ApiModelProperty("菜单的类型(1为普通菜单2为目录3为iFrame4为外部网站)") + @TableField("menu_type") + private Integer menuType; + + @ApiModelProperty("路由名称(需保持和前端对应的vue文件中的name保持一致defineOptions方法中设置的name)") + @TableField("router_name") + private String routerName; + + @ApiModelProperty("父菜单ID") + @TableField("parent_id") + private Long parentId; + + @ApiModelProperty("组件路径(对应前端项目view文件夹中的路径)") + @TableField("path") + private String path; + + @ApiModelProperty("是否按钮") + @TableField("is_button") + private Boolean isButton; + + @ApiModelProperty("权限标识") + @TableField("permission") + private String permission; + + @ApiModelProperty("路由元信息(前端根据这个信息进行逻辑处理)") + @TableField("meta_info") + private String metaInfo; + + @ApiModelProperty("菜单状态(1启用 0停用)") + @TableField("`status`") + private Integer status; + + @ApiModelProperty("备注") + @TableField("remark") + private String remark; + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java new file mode 100644 index 0000000..27d5171 --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java @@ -0,0 +1,21 @@ +package com.agileboot.system.menu.service; + +import cn.hutool.core.lang.tree.Tree; +import com.agileboot.common.satoken.pojo.LoginUser; +import com.agileboot.system.menu.pojo.dto.*; + +import java.util.List; + +public interface ISysMenuService { + List getMenuList(MenuQuery menuQuery); + + MenuDetailDTO getMenuInfo(Long menuId); + + List> getDropdownList(LoginUser loginUser); + + void addMenu(AddMenuCommand addCommand); + + void updateMenu(UpdateMenuCommand updateCommand); + + void remove(Long menuId); +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..0bbbd1a --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,130 @@ +package com.agileboot.system.menu.service.impl; + +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import com.agileboot.common.core.enums.common.MenuTypeEnum; +import com.agileboot.common.core.exception.BizException; +import com.agileboot.common.core.exception.error.ErrorCode; +import com.agileboot.common.core.utils.jackson.JacksonUtil; +import com.agileboot.common.satoken.pojo.LoginUser; +import com.agileboot.system.menu.mapper.SysMenuMapper; +import com.agileboot.system.menu.pojo.dto.*; +import com.agileboot.system.menu.pojo.entity.SysMenu; +import com.agileboot.system.menu.service.ISysMenuService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 菜单应用服务 + * + * @author valarchie + */ +@Service +@RequiredArgsConstructor +public class SysMenuServiceImpl extends ServiceImpl implements ISysMenuService { + + + @Override + public List getMenuList(MenuQuery query) { + Boolean isButton = query.getIsButton(); + List list = super.lambdaQuery() + .eq(isButton != null, SysMenu::getIsButton, isButton) + .orderByDesc(SysMenu::getParentId) + .list(); + return list.stream().map(MenuDTO::new) + .sorted(Comparator.comparing(MenuDTO::getRank, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + } + + @Override + public MenuDetailDTO getMenuInfo(Long menuId) { + SysMenu sysMenu = super.getById(menuId); + return new MenuDetailDTO(sysMenu); + } + + @Override + public List> getDropdownList(LoginUser loginUser) { + List menuEntityList = +// loginUser.isAdmin() ? + super.list(); +// : +// this.baseMapper.selectMenuListByUserId(loginUser.getUserId()); + + return buildMenuTreeSelect(menuEntityList); + } + + @Override + public void addMenu(AddMenuCommand addCommand) { + SysMenu entity = new SysMenu(); + BeanUtils.copyProperties(addCommand, entity, "menuId"); + String metaInfo = JacksonUtil.to(addCommand.getMeta()); + entity.setMetaInfo(metaInfo); + // 校验菜单名称是否唯一 + boolean exists = super.lambdaQuery() + .eq(SysMenu::getMenuName, addCommand.getMenuName()) + .eq(addCommand.getParentId() != null, SysMenu::getParentId, addCommand.getParentId()) + .exists(); + if (exists) throw new BizException(ErrorCode.Business.MENU_NAME_IS_NOT_UNIQUE); + + SysMenu parentMenu = super.getById(addCommand.getParentId()); + // Iframe和外链跳转类型 不允许添加按钮 + if (parentMenu != null && parentMenu.getIsButton() && ( + Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.IFRAME.getValue()) + || Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.OUTSIDE_LINK_REDIRECT.getValue()) + )) { + throw new BizException(ErrorCode.Business.MENU_NOT_ALLOWED_TO_CREATE_BUTTON_ON_IFRAME_OR_OUT_LINK); + } + // 只允许在目录菜单类型底下 添加子菜单 + if (parentMenu != null && !parentMenu.getIsButton() && ( + !Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.CATALOG.getValue()) + )) { + throw new BizException(ErrorCode.Business.MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG); + } + super.save(entity); + } + + @Override + public void updateMenu(UpdateMenuCommand updateCommand) { + + } + + @Override + public void remove(Long menuId) { + // 是否存在菜单子节点 + if (super.lambdaQuery().eq(SysMenu::getParentId, menuId).exists()) { + throw new BizException(ErrorCode.Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE); + } + // 查询菜单是否存在角色 + if (super.lambdaQuery().eq(SysMenu::getMenuId, menuId).exists()) { + throw new BizException(ErrorCode.Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE); + } + super.removeById(menuId); + } + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + public List> buildMenuTreeSelect(List menus) { + TreeNodeConfig config = new TreeNodeConfig(); + //默认为id可以不设置 + config.setIdKey("menuId"); + return TreeUtil.build(menus, 0L, config, (menu, tree) -> { + // 也可以使用 tree.setId(dept.getId());等一些默认值 + tree.setId(menu.getMenuId()); + tree.setParentId(menu.getParentId()); + tree.putExtra("label", menu.getMenuName()); + }); + } + +} diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/role/controller/pojo/entity/SysRoleMenu.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/role/controller/pojo/entity/SysRoleMenu.java new file mode 100644 index 0000000..8c4badc --- /dev/null +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/role/controller/pojo/entity/SysRoleMenu.java @@ -0,0 +1,46 @@ +package com.agileboot.system.role.controller.pojo.entity; + +import com.agileboot.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 角色和菜单关联表 + *

+ * + * @author valarchie + * @since 2022-10-02 + */ +@Getter +@Setter +@TableName("sys_role_menu") +@ApiModel(value = "SysRoleMenuXEntity对象", description = "角色和菜单关联表") +public class SysRoleMenu extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + @ApiModelProperty("角色ID") + @TableId(value = "role_id", type = IdType.AUTO) + private Long roleId; + + @ApiModelProperty("菜单ID") + @TableField("menu_id") + private Long menuId; + + + public Serializable pkVal() { + return this.menuId; + } + +}