master:系统菜单功能调整;

pull/1121/head
liujiang 2025-04-13 21:11:54 +08:00
parent 5d7af38398
commit 8b743d9dd7
22 changed files with 947 additions and 215 deletions

View File

@ -1,14 +1,17 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.vo.menu.*;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.dto.menu.MenuDTO;
import com.ruoyi.system.domain.dto.menu.MenuListDTO;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -20,56 +23,151 @@ import java.util.List;
*
* @author ruoyi
*/
@Api(tags = "菜单信息")
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends BaseController {
@Autowired
private ISysMenuService menuService;
public class SysMenuController extends XktBaseController {
final ISysMenuService menuService;
/**
*
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@GetMapping("/list")
public AjaxResult list(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menus);
@PreAuthorize("@ss.hasPermi('system:menu:add')")
@ApiOperation(value = "新增菜单", httpMethod = "POST", response = R.class)
@Log(title = "新增菜单", businessType = BusinessType.INSERT)
@PostMapping
public R<Integer> create(@Validated @RequestBody MenuVo menuVo) {
return R.ok(menuService.create(BeanUtil.toBean(menuVo, MenuDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@ApiOperation(value = "修改菜单", httpMethod = "PUT", response = R.class)
@Log(title = "修改菜单", businessType = BusinessType.UPDATE)
@PutMapping
public R<Integer> edit(@Validated @RequestBody MenuVo menuVo) {
return R.ok(menuService.update(BeanUtil.toBean(menuVo, MenuDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@ApiOperation(value = "根据菜单编号获取详细信息", httpMethod = "GET", response = R.class)
@GetMapping(value = "/{menuId}")
public AjaxResult getInfo(@PathVariable Long menuId) {
return success(menuService.selectMenuById(menuId));
public R<MenuResVo> getInfo(@PathVariable Long menuId) {
return R.ok(BeanUtil.toBean(menuService.getById(menuId), MenuResVo.class));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
@ApiOperation(value = "删除菜单", httpMethod = "DELETE", response = R.class)
@Log(title = "删除菜单", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public R<Integer> remove(@PathVariable("menuId") Long menuId) {
return R.ok(this.menuService.delete(menuId));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@ApiOperation(value = "获取菜单列表", httpMethod = "POST", response = R.class)
@PostMapping("/list")
public R<List<MenuResVo>> list(@Validated @RequestBody MenuListVo listVo) {
return R.ok(BeanUtil.copyToList(menuService.list(BeanUtil.toBean(listVo, MenuListDTO.class)), MenuResVo.class));
}
/**
*
*/
@GetMapping("/treeselect")
public AjaxResult treeselect(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menuService.buildMenuTreeSelect(menus));
@ApiOperation(value = "获取菜单下拉树列表", httpMethod = "POST", response = R.class)
@PostMapping("/treeSelect")
public R<List<TreeSelectVO>> treeSelect(@Validated @RequestBody MenuListVo listVo) {
return R.ok(BeanUtil.copyToList(menuService.treeSelect(BeanUtil.toBean(listVo, MenuListDTO.class)), TreeSelectVO.class));
}
/**
*
*/
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
@ApiOperation(value = "加载对应角色菜单列表树", httpMethod = "GET", response = R.class)
@GetMapping(value = "/roleMenuTreeSelect/{roleId}")
public R<UserRoleTreeSelectVO> roleMenuTreeSelect(@PathVariable("roleId") Long roleId) {
return R.ok(BeanUtil.toBean(menuService.roleMenuTreeSelect(roleId), UserRoleTreeSelectVO.class));
}
// ===============================================================================================
// ===============================================================================================
// ===============================================================================================
/**
*
*/
/* @PreAuthorize("@ss.hasPermi('system:menu:list')")
@GetMapping("/list")
public AjaxResult list(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menus);
}*/
/**
*
*//*
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping(value = "/{menuId}")
public AjaxResult getInfo(@PathVariable Long menuId) {
return success(menuService.selectMenuById(menuId));
}*/
/**
*
*/
/*@GetMapping("/treeselect")
public AjaxResult treeselect(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menuService.buildMenuTreeSelect(menus));
}*/
/**
*
*/
/*@GetMapping(value = "/roleMenuTreeselect/{roleId}")
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
List<SysMenu> menus = menuService.selectMenuList(getUserId());
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
return ajax;
}
}*/
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:add')")
/*@PreAuthorize("@ss.hasPermi('system:menu:add')")
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu) {
@ -80,12 +178,12 @@ public class SysMenuController extends BaseController {
}
menu.setCreateBy(getUsername());
return toAjax(menuService.insertMenu(menu));
}
}*/
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
/*@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu) {
@ -98,12 +196,12 @@ public class SysMenuController extends BaseController {
}
menu.setUpdateBy(getUsername());
return toAjax(menuService.updateMenu(menu));
}
}*/
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
/*@PreAuthorize("@ss.hasPermi('system:menu:remove')")
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public AjaxResult remove(@PathVariable("menuId") Long menuId) {
@ -114,5 +212,5 @@ public class SysMenuController extends BaseController {
return warn("菜单已分配,不允许删除");
}
return toAjax(menuService.deleteMenuById(menuId));
}
}*/
}

View File

@ -31,7 +31,7 @@ public class StoreCertVO {
private Long storeId;
@ApiModelProperty(value = "真实姓名", required = true)
@NotBlank(message = "真实姓名不能为空")
@Size(min = 1, max = 30, message = "真实姓名长度必须在1到30个字之间")
@Size(min = 0, max = 30, message = "真实姓名长度必须在1到30个字之间")
private String realName;
@ApiModelProperty(value = "联系电话", required = true)
@NotBlank(message = "联系电话不能为空")
@ -65,29 +65,29 @@ public class StoreCertVO {
private Integer soleProprietorshipType;
@ApiModelProperty(value = "营业执照名称", required = true)
@NotBlank(message = "营业执照名称不能为空")
@Size(min = 1, max = 100, message = "营业执照名称长度必须在1到100个字之间")
@Size(min = 0, max = 100, message = "营业执照名称长度必须在1到100个字之间")
private String licenseName;
@ApiModelProperty(value = "市场主体类型", required = true)
@NotNull(message = "市场主体类型不能为空")
private Integer marketEntryType;
@ApiModelProperty(value = "登记机关", required = true)
@NotBlank(message = "登记机关不能为空")
@Size(min = 1, max = 100, message = "登记机关长度必须在1到100个字之间")
@Size(min = 0, max = 100, message = "登记机关长度必须在1到100个字之间")
private String registerOrg;
@ApiModelProperty(value = "登记状态", required = true)
private Integer registerStatus;
@ApiModelProperty(value = "法定代表人/负责人名称", required = true)
@NotBlank(message = "法定代表人/负责人名称不能为空")
@Size(min = 1, max = 30, message = "法定代表人/负责人名称长度必须在1到30个字之间")
@Size(min = 0, max = 30, message = "法定代表人/负责人名称长度必须在1到30个字之间")
private String legalName;
@ApiModelProperty(value = "注册资本(万)")
private Integer registerCapital;
@ApiModelProperty(value = "实际经营地址", required = true)
@NotBlank(message = "实际经营地址不能为空")
@Size(min = 1, max = 100, message = "实际经营地址长度必须在1到100个字之间")
@Size(min = 0, max = 100, message = "实际经营地址长度必须在1到100个字之间")
private String realBusinessAddress;
@ApiModelProperty(value = "经营范围")
@Size(min = 1, max = 500, message = "经营范围长度必须在1到500个字之间")
@Size(min = 0, max = 500, message = "经营范围长度必须在1到500个字之间")
private String businessScope;
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "营业期限开始时间")

View File

@ -34,14 +34,14 @@ public class StoreProdVO {
@NotNull(message = "商品分类ID不能为空!")
private Long prodCateId;
@ApiModelProperty(value = "工厂货号")
@Size(min = 1, max = 15, message = "工厂货号不能超过60个字!")
@Size(min = 0, max = 15, message = "工厂货号不能超过60个字!")
private String factoryArtNum;
@ApiModelProperty(value = "商品货号", required = true)
@Size(min = 1, max = 15, message = "商品货号不能超过60个字!")
@Size(min = 0, max = 15, message = "商品货号不能超过60个字!")
@NotBlank(message = "商品货号不能为空!")
private String prodArtNum;
@ApiModelProperty(value = "商品标题", required = true)
@Size(min = 1, max = 60, message = "商品标题不能超过60个字!")
@Size(min = 0, max = 60, message = "商品标题不能超过60个字!")
@NotBlank(message = "商品标题不能为空!")
private String prodTitle;
@ApiModelProperty(value = "商品重量")

View File

@ -27,7 +27,7 @@ public class StoreRoleVO {
private Long storeRoleId;
@ApiModelProperty(value = "角色名称")
@NotBlank(message = "角色名称不能为空!")
@Size(min = 1, max = 30, message = "角色名称长度不能超过30个字!")
@Size(min = 0, max = 30, message = "角色名称长度不能超过30个字!")
private String roleName;
@ApiModelProperty(value = "档口子角色备注")
private String remark;

View File

@ -22,7 +22,7 @@ public class StoreRoleAccUpdateVO {
@NotNull(message = "档口子账号ID不能为空!")
private Long storeRoleAccId;
@ApiModelProperty(value = "子账户名称")
@Size(min = 1, max = 30, message = "子账户名称长度不能超过30个字!")
@Size(min = 0, max = 30, message = "子账户名称长度不能超过30个字!")
private String accountName;
@ApiModelProperty(value = "档口子角色ID")
@NotNull(message = "档口子角色ID不能为空!")

View File

@ -27,7 +27,7 @@ public class StoreRoleAccVO {
@NotNull(message = "档口子角色ID不能为空!")
private Long storeRoleId;
@ApiModelProperty(value = "子账户名称")
@Size(min = 1, max = 30, message = "子账户名称长度不能超过30个字!")
@Size(min = 0, max = 30, message = "子账户名称长度不能超过30个字!")
private String accountName;
@ApiModelProperty(value = "用户ID用户已注册时传未注册则不传")
private Long userId;

View File

@ -43,7 +43,7 @@ public class TreeSelect implements Serializable {
public TreeSelect(SysMenu menu) {
this.id = menu.getMenuId();
this.label = menu.getMenuName();
this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
// this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
}
public Long getId() {

View File

@ -1,26 +1,27 @@
package com.ruoyi.common.core.domain.entity;
import com.ruoyi.common.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.ruoyi.common.core.domain.XktBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
/**
* sys_menu
*
* @author ruoyi
*/
public class SysMenu extends BaseEntity {
@EqualsAndHashCode(callSuper = true)
@Data
public class SysMenu extends XktBaseEntity {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "menu_id")
private Long menuId;
/**
@ -28,11 +29,6 @@ public class SysMenu extends BaseEntity {
*/
private String menuName;
/**
*
*/
private String parentName;
/**
* ID
*/
@ -98,154 +94,6 @@ public class SysMenu extends BaseEntity {
*/
private String icon;
/**
*
*/
private List<SysMenu> children = new ArrayList<SysMenu>();
public Long getMenuId() {
return menuId;
}
public void setMenuId(Long menuId) {
this.menuId = menuId;
}
@NotBlank(message = "菜单名称不能为空")
@Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
@NotNull(message = "显示顺序不能为空")
public Integer getOrderNum() {
return orderNum;
}
public void setOrderNum(Integer orderNum) {
this.orderNum = orderNum;
}
@Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
public String getComponent() {
return component;
}
public void setComponent(String component) {
this.component = component;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public String getRouteName() {
return routeName;
}
public void setRouteName(String routeName) {
this.routeName = routeName;
}
public String getIsFrame() {
return isFrame;
}
public void setIsFrame(String isFrame) {
this.isFrame = isFrame;
}
public String getIsCache() {
return isCache;
}
public void setIsCache(String isCache) {
this.isCache = isCache;
}
@NotBlank(message = "菜单类型不能为空")
public String getMenuType() {
return menuType;
}
public void setMenuType(String menuType) {
this.menuType = menuType;
}
public String getVisible() {
return visible;
}
public void setVisible(String visible) {
this.visible = visible;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
public String getPerms() {
return perms;
}
public void setPerms(String perms) {
this.perms = perms;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public List<SysMenu> getChildren() {
return children;
}
public void setChildren(List<SysMenu> children) {
this.children = children;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)

View File

@ -0,0 +1,23 @@
package com.ruoyi.common.core.domain.vo.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单返回数据")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuListVo {
@ApiModelProperty(value = "菜单名称")
private String menuName;
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.common.core.domain.vo.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单返回数据")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuResVo {
@ApiModelProperty(value = "菜单主键, 新增不传 编辑必传")
private Long menuId;
@ApiModelProperty(value = "菜单名称")
private String menuName;
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
@ApiModelProperty(value = "显示顺序")
private Integer orderNum;
@ApiModelProperty(value = "路由地址")
private String path;
@ApiModelProperty(value = "组件路径")
private String component;
@ApiModelProperty(value = "路由参数")
private String query;
@ApiModelProperty(value = "路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义")
private String routeName;
@ApiModelProperty(value = "是否为外链0是 1否")
private String isFrame;
@ApiModelProperty(value = "是否缓存0缓存 1不缓存")
private String isCache;
@ApiModelProperty(value = "类型M目录 C菜单 F按钮")
private String menuType;
@ApiModelProperty(value = "显示状态0显示 1隐藏")
private String visible;
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
@ApiModelProperty(value = "权限字符串")
private String perms;
@ApiModelProperty(value = "菜单图标")
private String icon;
}

View File

@ -0,0 +1,62 @@
package com.ruoyi.common.core.domain.vo.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单管理")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuVo {
@ApiModelProperty(value = "菜单主键, 新增不传 编辑必传")
private Long menuId;
@ApiModelProperty(value = "菜单名称")
@NotBlank(message = "菜单名称不能为空")
@Size(min = 1, max = 50, message = "菜单名称长度不能超过50个字")
private String menuName;
@NotNull(message = "父菜单ID不能为空")
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
@NotNull(message = "显示顺序不能为空")
@ApiModelProperty(value = "显示顺序")
private Integer orderNum;
@ApiModelProperty(value = "路由地址")
@Size(min = 1, max = 200, message = "路由地址不能超过200个字")
private String path;
@ApiModelProperty(value = "组件路径")
@Size(min = 1, max = 200, message = "组件路径不能超过255个字")
private String component;
@ApiModelProperty(value = "路由参数")
private String query;
@ApiModelProperty(value = "路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义")
private String routeName;
@ApiModelProperty(value = "是否为外链0是 1否")
private String isFrame;
@ApiModelProperty(value = "是否缓存0缓存 1不缓存")
private String isCache;
@NotBlank(message = "菜单类型不能为空")
@ApiModelProperty(value = "类型M目录 C菜单 F按钮")
private String menuType;
@ApiModelProperty(value = "显示状态0显示 1隐藏")
private String visible;
@NotBlank(message = "菜单状态不能为空")
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
@ApiModelProperty(value = "权限字符串")
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
private String perms;
@ApiModelProperty(value = "菜单图标")
private String icon;
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.common.core.domain.vo.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* Treeselect
*
* @author ruoyi
*/
@Data
public class TreeSelectVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "节点ID")
private Long id;
@ApiModelProperty(value = "节点名称")
private String label;
@ApiModelProperty(value = "节点禁用")
private boolean disabled = false;
@ApiModelProperty(value = "子节点")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<TreeSelectVO> children;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.common.core.domain.vo.menu;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
*
*
* @author ruoyi
*/
@Data
public class UserRoleTreeSelectVO implements Serializable {
@ApiModelProperty(value = "用户选中的菜单")
List<Long> checkedIdList;
@ApiModelProperty(value = "菜单树")
List<TreeSelectVO> tree;
}

View File

@ -0,0 +1,51 @@
package com.ruoyi.system.domain.dto.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单管理")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuDTO {
@ApiModelProperty(value = "菜单主键, 新增不传 编辑必传")
private Long menuId;
@ApiModelProperty(value = "菜单名称")
private String menuName;
@ApiModelProperty(value = "父菜单名称")
private String parentName;
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
@ApiModelProperty(value = "显示顺序")
private Integer orderNum;
@ApiModelProperty(value = "路由地址")
private String path;
@ApiModelProperty(value = "组件路径")
private String component;
@ApiModelProperty(value = "路由参数")
private String query;
@ApiModelProperty(value = "路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义")
private String routeName;
@ApiModelProperty(value = "是否为外链0是 1否")
private String isFrame;
@ApiModelProperty(value = "是否缓存0缓存 1不缓存")
private String isCache;
@ApiModelProperty(value = "类型M目录 C菜单 F按钮")
private String menuType;
@ApiModelProperty(value = "显示状态0显示 1隐藏")
private String visible;
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
@ApiModelProperty(value = "权限字符串")
private String perms;
@ApiModelProperty(value = "菜单图标")
private String icon;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.system.domain.dto.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单返回数据")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuListDTO {
@ApiModelProperty(value = "菜单名称")
private String menuName;
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
}

View File

@ -0,0 +1,55 @@
package com.ruoyi.system.domain.dto.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("系统菜单返回数据")
@Data
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuResDTO {
@ApiModelProperty(value = "菜单主键, 新增不传 编辑必传")
private Long menuId;
@ApiModelProperty(value = "菜单名称")
private String menuName;
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
@ApiModelProperty(value = "显示顺序")
private Integer orderNum;
@ApiModelProperty(value = "路由地址")
private String path;
@ApiModelProperty(value = "组件路径")
private String component;
@ApiModelProperty(value = "路由参数")
private String query;
@ApiModelProperty(value = "路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义")
private String routeName;
@ApiModelProperty(value = "是否为外链0是 1否")
private String isFrame;
@ApiModelProperty(value = "是否缓存0缓存 1不缓存")
private String isCache;
@ApiModelProperty(value = "类型M目录 C菜单 F按钮")
private String menuType;
@ApiModelProperty(value = "显示状态0显示 1隐藏")
private String visible;
@ApiModelProperty(value = "菜单状态0正常 1停用")
private String status;
@ApiModelProperty(value = "权限字符串")
private String perms;
@ApiModelProperty(value = "菜单图标")
private String icon;
@ApiModelProperty(value = "子菜单")
List<MenuResDTO> children;
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.system.domain.dto.menu;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* Treeselect
*
* @author ruoyi
*/
@Data
public class TreeSelectDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "节点ID")
private Long id;
@ApiModelProperty(value = "节点名称")
private String label;
@ApiModelProperty(value = "节点禁用")
private boolean disabled = false;
@ApiModelProperty(value = "子节点")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<TreeSelectDTO> children;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.system.domain.dto.menu;
import com.ruoyi.common.core.domain.vo.menu.TreeSelectVO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
*
*
* @author ruoyi
*/
@Data
public class UserRoleTreeSelectDTO implements Serializable {
@ApiModelProperty(value = "用户选中的菜单")
List<Long> checkedIdList;
@ApiModelProperty(value = "菜单树")
List<TreeSelectDTO> tree;
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.system.domain.vo.menu.SysMenuDTO;
import org.apache.ibatis.annotations.Param;
@ -11,7 +12,7 @@ import java.util.List;
*
* @author ruoyi
*/
public interface SysMenuMapper {
public interface SysMenuMapper extends BaseMapper<SysMenu> {
/**
*
*
@ -35,6 +36,18 @@ public interface SysMenuMapper {
*/
public List<SysMenu> selectMenuListByUserId(SysMenu menu);
/**
* userId
*
* @param menuName
* @param status
* @param userId ID
* @return List<SysMenu>
*/
List<SysMenu> getMenuListByUserId(@Param("menuName") String menuName,
@Param("status") String status,
@Param("userId") Long userId);
/**
* ID
*
@ -126,4 +139,5 @@ public interface SysMenuMapper {
List<SysMenuDTO> selectMenuListByRoleIdAndMenuType(@Param("roleId") Long roleId, @Param("menuType") String menuType);
}

View File

@ -2,6 +2,9 @@ package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.vo.menu.MenuResVo;
import com.ruoyi.common.core.domain.vo.menu.UserRoleTreeSelectVO;
import com.ruoyi.system.domain.dto.menu.*;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.domain.vo.menu.SysMenuDTO;
@ -151,4 +154,49 @@ public interface ISysMenuService {
* @return
*/
public boolean checkMenuNameUnique(SysMenu menu);
/**
*
* @param menuDTO
* @return Integer
*/
Integer create(MenuDTO menuDTO);
/**
*
* @param menuDTO
* @return Integer
*/
Integer update(MenuDTO menuDTO);
/**
*
* @param menuId ID
* @return MenuResDTO
*/
MenuResDTO getById(Long menuId);
/**
*
* @param menuId ID
* @return Integer
*/
Integer delete(Long menuId);
List<MenuResDTO> list(MenuListDTO listDTO);
/**
*
* @param listDTO
* @return List<MenuResDTO>
*/
List<TreeSelectDTO> treeSelect(MenuListDTO listDTO);
/**
*
* @param roleId ID
* @return UserRoleTreeSelectDTO
*/
UserRoleTreeSelectDTO roleMenuTreeSelect(Long roleId);
}

View File

@ -1,13 +1,18 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.dto.menu.*;
import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.domain.vo.menu.SysMenuDTO;
@ -15,29 +20,344 @@ import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.mapper.SysRoleMenuMapper;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;
import static com.ruoyi.common.utils.SecurityUtils.getUsername;
/**
*
*
* @author ruoyi
*/
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl implements ISysMenuService {
public static final String PREMISSION_STRING = "perms[\"{0}\"]";
@Autowired
private SysMenuMapper menuMapper;
final SysMenuMapper menuMapper;
final SysRoleMapper roleMapper;
final SysRoleMenuMapper roleMenuMapper;
/**
*
*
* @param menuDTO
* @return Integer
*/
@Override
@Transactional
public Integer create(MenuDTO menuDTO) {
if (ObjectUtils.isNotEmpty(menuDTO.getMenuId())) {
throw new ServiceException("新增菜单失败menuId必须为空!", HttpStatus.ERROR);
}
if (!this.checkMenuNameUnique(menuDTO.getMenuId(), menuDTO.getMenuName(), menuDTO.getParentId())) {
throw new ServiceException("新增菜单'" + menuDTO.getMenuName() + "'失败,菜单名称已存在", HttpStatus.ERROR);
} else if (UserConstants.YES_FRAME.equals(menuDTO.getIsFrame()) && !StringUtils.ishttp(menuDTO.getPath())) {
throw new ServiceException("新增菜单'" + menuDTO.getMenuName() + "'失败地址必须以http(s)://开头", HttpStatus.ERROR);
}
SysMenu menu = BeanUtil.toBean(menuDTO, SysMenu.class);
menu.setCreateBy(getUsername());
return this.menuMapper.insert(menu);
}
/**
*
*
* @param menuDTO
* @return Integer
*/
@Override
@Transactional
public Integer update(MenuDTO menuDTO) {
// 编辑menuId不能为空
Optional.ofNullable(menuDTO.getMenuId()).orElseThrow(() -> new ServiceException("菜单ID不能为空!", HttpStatus.ERROR));
if (!this.checkMenuNameUnique(menuDTO.getMenuId(), menuDTO.getMenuName(), menuDTO.getParentId())) {
throw new ServiceException("修改菜单'" + menuDTO.getMenuName() + "'失败,菜单名称已存在", HttpStatus.ERROR);
} else if (UserConstants.YES_FRAME.equals(menuDTO.getIsFrame()) && !StringUtils.ishttp(menuDTO.getPath())) {
throw new ServiceException("修改菜单'" + menuDTO.getMenuName() + "'失败地址必须以http(s)://开头", HttpStatus.ERROR);
} else if (menuDTO.getMenuId().equals(menuDTO.getParentId())) {
throw new ServiceException("修改菜单'" + menuDTO.getMenuName() + "'失败,上级菜单不能选择自己");
}
SysMenu menu = Optional.ofNullable(this.menuMapper.selectOne(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getMenuId, menuDTO.getMenuId()).eq(SysMenu::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("菜单不存在!", HttpStatus.ERROR));
menu.setUpdateBy(getUsername());
menu.setUpdateTime(new Date());
BeanUtil.copyProperties(menuDTO, menu);
return this.menuMapper.updateById(menu);
}
/**
*
*
* @param menuId ID
* @return MenuResDTO
*/
@Override
@Transactional(readOnly = true)
public MenuResDTO getById(Long menuId) {
SysMenu menu = Optional.ofNullable(this.menuMapper.selectOne(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getMenuId, menuId).eq(SysMenu::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("菜单不存在!", HttpStatus.ERROR));
return BeanUtil.toBean(menu, MenuResDTO.class).setMenuId(menuId);
}
/**
*
*
* @param menuId ID
* @return Integer
*/
@Override
@Transactional
public Integer delete(Long menuId) {
SysMenu menu = Optional.ofNullable(this.menuMapper.selectOne(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getMenuId, menuId).eq(SysMenu::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("菜单不存在!", HttpStatus.ERROR));
if (this.hasChildByMenuId(menuId)) {
throw new ServiceException("存在子菜单,不允许删除", HttpStatus.ERROR);
}
if (this.checkMenuExistRole(menuId)) {
throw new ServiceException("菜单已分配,不允许删除", HttpStatus.ERROR);
}
menu.setDelFlag(Constants.DELETED);
return this.menuMapper.updateById(menu);
}
@Override
@Transactional(readOnly = true)
public List<MenuResDTO> list(MenuListDTO listDTO) {
Long userId = getUserId();
List<SysMenu> menuList = null;
// 管理员显示所有菜单信息
if (SysUser.isAdmin(userId)) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getDelFlag, Constants.UNDELETED);
if (StringUtils.isNotBlank(listDTO.getMenuName())) {
queryWrapper.like(SysMenu::getMenuName, listDTO.getMenuName());
}
if (StringUtils.isNotBlank(listDTO.getStatus())) {
queryWrapper.eq(SysMenu::getStatus, listDTO.getStatus());
}
menuList = this.menuMapper.selectList(queryWrapper);
} else {
menuList = this.menuMapper.getMenuListByUserId(listDTO.getMenuName(), listDTO.getStatus(), userId);
}
return BeanUtil.copyToList(menuList, MenuResDTO.class);
}
/**
*
*
* @param listDTO
* @return List<MenuResDTO>
*/
@Override
@Transactional(readOnly = true)
public List<TreeSelectDTO> treeSelect(MenuListDTO listDTO) {
List<MenuResDTO> list = this.list(listDTO);
if (CollectionUtils.isEmpty(list)) {
return new ArrayList<>();
}
List<MenuResDTO> menuTrees = getMenuTree(list);
return menuTrees.stream().map(x -> new TreeSelectDTO() {{
setId(x.getMenuId());
setLabel(x.getMenuName());
setChildren(x.getChildren().stream().map(x -> new TreeSelectDTO() {{
setId(x.getMenuId());
setLabel(x.getMenuName());
}}).collect(Collectors.toList()));
}}).collect(Collectors.toList());
}
/**
*
*
* @param roleId ID
* @return UserRoleTreeSelectDTO
*/
@Override
@Transactional(readOnly = true)
public UserRoleTreeSelectDTO roleMenuTreeSelect(Long roleId) {
// 当前用户所有的菜单
List<MenuResDTO> list = this.list(new MenuListDTO());
// 用户选中的菜单
List<Long> checkedIdList = this.selectMenuListByRoleId(roleId);
// 将用户的菜单转化为tree
List<MenuResDTO> menuTrees = getMenuTree(list);
List<TreeSelectDTO> tree = menuTrees.stream().map(x -> new TreeSelectDTO() {{
setId(x.getMenuId());
setLabel(x.getMenuName());
setChildren(x.getChildren().stream().map(x -> new TreeSelectDTO() {{
setId(x.getMenuId());
setLabel(x.getMenuName());
}}).collect(Collectors.toList()));
}}).collect(Collectors.toList());
return new UserRoleTreeSelectDTO() {{
setTree(tree);
setCheckedIdList(checkedIdList);
}};
}
/**
*
*
* @param menus
* @return
*/
private List<MenuResDTO> getMenuTree(List<MenuResDTO> menus) {
List<MenuResDTO> returnList = new ArrayList<>();
List<Long> tempList = menus.stream().map(MenuResDTO::getMenuId).collect(Collectors.toList());
for (Iterator<MenuResDTO> iterator = menus.iterator(); iterator.hasNext(); ) {
MenuResDTO menu = iterator.next();
// 如果是顶级节点, 遍历该父节点的所有子节点
if (!tempList.contains(menu.getParentId())) {
recursionFn(menus, menu);
returnList.add(menu);
}
}
if (returnList.isEmpty()) {
returnList = menus;
}
return returnList;
}
/**
*
*
* @param list
* @param t
*/
private void recursionFn(List<MenuResDTO> list, MenuResDTO t) {
// 得到子节点列表
List<MenuResDTO> childList = getChildList(list, t);
t.setChildren(childList);
for (MenuResDTO tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
/**
*
*/
private List<MenuResDTO> getChildList(List<MenuResDTO> list, MenuResDTO t) {
List<MenuResDTO> tlist = new ArrayList<>();
Iterator<MenuResDTO> it = list.iterator();
while (it.hasNext()) {
MenuResDTO n = it.next();
if (n.getParentId().longValue() == t.getMenuId().longValue()) {
tlist.add(n);
}
}
return tlist;
}
/**
*
*/
private boolean hasChild(List<MenuResDTO> list, MenuResDTO t) {
return getChildList(list, t).size() > 0;
}
/**
*
*
* @param menu
* @return
*/
private Boolean checkMenuNameUnique(Long id, String menuName, Long parentId) {
Long menuId = ObjectUtils.defaultIfNull(id, -1L);
SysMenu info = menuMapper.checkMenuNameUnique(menuName, parentId);
if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
return UserConstants.NOT_UNIQUE;
}
return UserConstants.UNIQUE;
}
@Autowired
private SysRoleMapper roleMapper;
@Autowired
private SysRoleMenuMapper roleMenuMapper;
/**
*
@ -76,7 +396,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
if (SysUser.isAdmin(userId)) {
menuList = menuMapper.selectMenuList(menu);
} else {
menu.getParams().put("userId", userId);
// menu.getParams().put("userId", userId);
menuList = menuMapper.selectMenuListByUserId(menu);
}
return menuList;
@ -164,7 +484,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
router.setComponent(getComponent(menu));
router.setQuery(menu.getQuery());
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
List<SysMenu> cMenus = menu.getChildren();
List<SysMenu> cMenus = new ArrayList<>();
// List<SysMenu> cMenus = menu.getChildren();
if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
router.setAlwaysShow(true);
router.setRedirect("noRedirect");
@ -318,6 +641,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
return UserConstants.UNIQUE;
}
/**
*
*
@ -446,7 +770,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
private void recursionFn(List<SysMenu> list, SysMenu t) {
// 得到子节点列表
List<SysMenu> childList = getChildList(list, t);
t.setChildren(childList);
// t.setChildren(childList);
for (SysMenu tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);

View File

@ -54,7 +54,8 @@
from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
order by m.parent_id, m.order_num
</select>
<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m
@ -219,4 +220,35 @@
AND srm.role_id = #{roleId}
</select>
<select id="getMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id
left join sys_role ro on ur.role_id = ro.role_id
where ur.user_id = #{userId}
<if test="menuName != null and menuName != ''">
AND m.menu_name like concat('%', #{menuName}, '%')
</if>
<if test="visible != null and visible != ''">
AND m.visible = #{visible}
</if>
<if test="status != null and status != ''">
AND m.status = #{status}
</if>
order by m.parent_id, m.order_num
</select>
</mapper>