feat:app端权限管理修改及功能导航模块

main
HuangHuiKang 17 hours ago
parent 3984fbe953
commit 84c6c16278

@ -24,6 +24,7 @@ public interface ErrorCodeConstants {
ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "菜单不存在");
ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除");
ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单");
ErrorCode MENU_CLIENT_TYPE_INCONSISTENT = new ErrorCode(1_002_001_006, "菜单端类型不一致,请选择同一端的菜单进行分配");
// ========== 角色模块 1-002-002-000 ==========
ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在");
@ -163,6 +164,8 @@ public interface ErrorCodeConstants {
// ========== 站内信发送 1-002-028-000 ==========
ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失");
ErrorCode IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_029_000, "导入数据不能为空!");
ErrorCode IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_028_001, "导入数据不能为空!");
// ========== app功能导航模块 1-002-029-000 ==========
ErrorCode USER_NAV_MENU_NOT_EXISTS = new ErrorCode(1_002_029_000, "App用户导航菜单配置不存在");
}

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
@ -33,6 +34,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -91,7 +93,7 @@ public class AuthController {
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo(@RequestParam(value = "clientType", required = false) Integer clientType) {
// 1.1 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
@ -109,6 +111,7 @@ public class AuthController {
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = menuService.getMenuList(menuIds);
menuList.removeIf(menu -> !Objects.equals(menu.getClientType(), clientType));
menuList = menuService.filterDisableMenus(menuList);
// 2. 拼接结果返回
@ -162,3 +165,4 @@ public class AuthController {
}
}

@ -89,6 +89,8 @@ public class AuthPermissionInfoRespVO {
@Schema(description = "菜单英文名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
private String enName;
@Schema(description = "菜单类型")
private Integer type;
/**
*
*/

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuRe
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -69,9 +70,11 @@ public class MenuController {
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" +
"在多租户的场景下,会只返回租户所在套餐有的菜单")
public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() {
public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList(
@RequestParam(value = "clientType", required = false) Integer clientType) {
List<MenuDO> list = menuService.getMenuListByTenant(
new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())
.setClientType(clientType == null ? MenuClientTypeEnum.WEB.getType() : clientType));
list = menuService.filterDisableMenus(list);
list.sort(Comparator.comparing(MenuDO::getSort));
return success(BeanUtils.toBean(list, MenuSimpleRespVO.class));

@ -5,6 +5,9 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -16,8 +19,12 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Objects;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
@ -33,14 +40,23 @@ public class PermissionController {
@Resource
private PermissionService permissionService;
@Resource
private MenuService menuService;
@Resource
private TenantService tenantService;
@Operation(summary = "获得角色拥有的菜单编号")
@Parameter(name = "roleId", description = "角色编号", required = true)
@GetMapping("/list-role-menus")
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
return success(permissionService.getRoleMenuListByRoleId(roleId));
public CommonResult<Set<Long>> getRoleMenuList(
@RequestParam("roleId") Long roleId,
@RequestParam(value = "clientType", required = false) Integer clientType) {
clientType = clientType == null ? MenuClientTypeEnum.WEB.getType() : clientType;
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(roleId);
List<MenuDO> menus = menuService.getMenuList(menuIds);
Integer finalClientType = clientType;
menus.removeIf(menu -> !Objects.equals(menu.getClientType(), finalClientType));
return success(convertSet(menus, MenuDO::getId));
}
@PostMapping("/assign-role-menu")

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Schema(description = "管理后台 - 菜单列表 Request VO")
@Data
@Accessors(chain = true)
public class MenuListReqVO {
@Schema(description = "菜单名称,模糊匹配", example = "芋道")
@ -16,4 +19,7 @@ public class MenuListReqVO {
@Schema(description = "菜单英文名称,模糊匹配", example = "yudao")
private String enName;
@Schema(description = "菜单端类型,参见 MenuClientTypeEnum 枚举类", example = "1")
private Integer clientType = MenuClientTypeEnum.WEB.getType();
}

@ -73,4 +73,7 @@ public class MenuRespVO {
@Size(max = 50, message = "菜单英文名称长度不能超过50个字符")
private String enName;
@Schema(description = "菜单端类型,参见 MenuClientTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer clientType;
}

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -66,4 +67,8 @@ public class MenuSaveVO {
@Size(max = 50, message = "菜单英文名称长度不能超过50个字符")
private String enName;
@Schema(description = "菜单端类型,参见 MenuClientTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "菜单端类型不能为空")
private Integer clientType = MenuClientTypeEnum.WEB.getType();
}

@ -26,4 +26,7 @@ public class MenuSimpleRespVO {
@Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer type;
@Schema(description = "菜单端类型,参见 MenuClientTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer clientType;
}

@ -0,0 +1,113 @@
package cn.iocoder.yudao.module.system.controller.admin.usernavmenu;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.usernavmenu.UserNavMenuDO;
import cn.iocoder.yudao.module.system.service.usernavmenu.UserNavMenuService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@Tag(name = "管理后台 - App用户导航菜单配置")
@RestController
@RequestMapping("/system/user-nav-menu")
@Validated
public class UserNavMenuController {
@Resource
private UserNavMenuService userNavMenuService;
@PostMapping("/create")
@Operation(summary = "创建App用户导航菜单配置")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:create')")
public CommonResult<Long> createUserNavMenu(@Valid @RequestBody UserNavMenuSaveReqVO createReqVO) {
return success(userNavMenuService.createUserNavMenu(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新App用户导航菜单配置")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:update')")
public CommonResult<Boolean> updateUserNavMenu(@Valid @RequestBody UserNavMenuSaveReqVO updateReqVO) {
userNavMenuService.updateUserNavMenu(updateReqVO);
return success(true);
}
@PutMapping("/update-list")
@Operation(summary = "批量更新")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:update')")
public CommonResult<Boolean> updateUserNavMenuList(@Valid @RequestBody List<UserNavMenuSaveReqVO> updateReqVOList) {
userNavMenuService.updateUserNavMenuList(updateReqVOList);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除App用户导航菜单配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:delete')")
public CommonResult<Boolean> deleteUserNavMenu(@RequestParam("id") Long id) {
userNavMenuService.deleteUserNavMenu(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得App用户导航菜单配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:query')")
public CommonResult<UserNavMenuRespVO> getUserNavMenu(@RequestParam("id") Long id) {
UserNavMenuDO userNavMenu = userNavMenuService.getUserNavMenu(id);
return success(BeanUtils.toBean(userNavMenu, UserNavMenuRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得App用户导航菜单配置列表")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:query')")
public CommonResult<List<UserNavMenuRespVO>> getUserNavMenuList(@Valid UserNavMenuPageReqVO listReqVO) {
List<UserNavMenuDO> list = userNavMenuService.getUserNavMenuList(listReqVO);
return success(BeanUtils.toBean(list, UserNavMenuRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得App用户导航菜单配置分页")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:query')")
public CommonResult<PageResult<UserNavMenuRespVO>> getUserNavMenuPage(@Valid UserNavMenuPageReqVO pageReqVO) {
PageResult<UserNavMenuDO> pageResult = userNavMenuService.getUserNavMenuPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, UserNavMenuRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出App用户导航菜单配置 Excel")
@PreAuthorize("@ss.hasPermission('system:user-nav-menu:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportUserNavMenuExcel(@Valid UserNavMenuPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<UserNavMenuDO> list = userNavMenuService.getUserNavMenuPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "App用户导航菜单配置.xls", "数据", UserNavMenuRespVO.class,
BeanUtils.toBean(list, UserNavMenuRespVO.class));
}
}

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - App用户导航菜单配置分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class UserNavMenuPageReqVO extends PageParam {
@Schema(description = "用户ID", example = "31069")
private Long userId;
@Schema(description = "菜单ID", example = "22337")
private Long menuId;
@Schema(description = "显示顺序")
private Integer sort;
@Schema(description = "状态0正常 1停用", example = "1")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - App用户导航菜单配置 Response VO")
@Data
@ExcelIgnoreUnannotated
public class UserNavMenuRespVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "17857")
@ExcelProperty("ID")
private Long id;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31069")
@ExcelProperty("用户ID")
private Long userId;
@Schema(description = "菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "22337")
@ExcelProperty("菜单ID")
private Long menuId;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("显示顺序")
private Integer sort;
@Schema(description = "状态0正常 1停用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("状态0正常 1停用")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - App用户导航菜单配置新增/修改 Request VO")
@Data
public class UserNavMenuSaveReqVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "17857")
private Long id;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31069")
@NotNull(message = "用户ID不能为空")
private Long userId;
@Schema(description = "菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "22337")
@NotNull(message = "菜单ID不能为空")
private Long menuId;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "状态0正常 1停用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态0正常 1停用不能为空")
private Integer status;
}

@ -52,6 +52,7 @@ public interface AuthConvert {
.keepAlive(menu.getKeepAlive())
.alwaysShow(menu.getAlwaysShow())
.enName(menu.getEnName())
.type(menu.getType())
.build();
}

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.permission;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
@ -108,5 +109,12 @@ public class MenuDO extends BaseDO {
*/
private String enName;
/**
*
*
* {@link MenuClientTypeEnum}
*/
private Integer clientType;
}

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.system.dal.dataobject.usernavmenu;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* App DO
*
* @author
*/
@TableName("system_user_nav_menu")
@KeySequence("system_user_nav_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserNavMenuDO extends BaseDO {
/**
* ID
*/
@TableId
private Long id;
/**
* ID
*/
private Long userId;
/**
* ID
*/
private Long menuId;
/**
*
*/
private Integer sort;
/**
* 0 1
*/
private Integer status;
}

@ -15,6 +15,13 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
return selectOne(MenuDO::getParentId, parentId, MenuDO::getName, name);
}
default MenuDO selectByParentIdAndNameAndClientType(Long parentId, String name, Integer clientType) {
return selectOne(new LambdaQueryWrapperX<MenuDO>()
.eq(MenuDO::getParentId, parentId)
.eq(MenuDO::getName, name)
.eq(MenuDO::getClientType, clientType));
}
default Long selectCountByParentId(Long parentId) {
return selectCount(MenuDO::getParentId, parentId);
}
@ -23,7 +30,8 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
return selectList(new LambdaQueryWrapperX<MenuDO>()
.likeIfPresent(MenuDO::getName, reqVO.getName())
.likeIfPresent(MenuDO::getEnName, reqVO.getEnName())
.eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
.eqIfPresent(MenuDO::getStatus, reqVO.getStatus())
.eqIfPresent(MenuDO::getClientType, reqVO.getClientType()));
}
default List<MenuDO> selectListByPermission(String permission) {

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.system.dal.mysql.usernavmenu;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.usernavmenu.UserNavMenuDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo.*;
/**
* App Mapper
*
* @author
*/
@Mapper
public interface UserNavMenuMapper extends BaseMapperX<UserNavMenuDO> {
default int deleteByUserId(Long userId) {
return delete(new LambdaQueryWrapperX<UserNavMenuDO>().eq(UserNavMenuDO::getUserId, userId));
}
default List<UserNavMenuDO> selectList(UserNavMenuPageReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<UserNavMenuDO>()
.eqIfPresent(UserNavMenuDO::getUserId, reqVO.getUserId())
.eqIfPresent(UserNavMenuDO::getMenuId, reqVO.getMenuId())
.eqIfPresent(UserNavMenuDO::getSort, reqVO.getSort())
.eqIfPresent(UserNavMenuDO::getStatus, reqVO.getStatus())
.betweenIfPresent(UserNavMenuDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(UserNavMenuDO::getId));
}
default PageResult<UserNavMenuDO> selectPage(UserNavMenuPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<UserNavMenuDO>()
.eqIfPresent(UserNavMenuDO::getUserId, reqVO.getUserId())
.eqIfPresent(UserNavMenuDO::getMenuId, reqVO.getMenuId())
.eqIfPresent(UserNavMenuDO::getSort, reqVO.getSort())
.eqIfPresent(UserNavMenuDO::getStatus, reqVO.getStatus())
.betweenIfPresent(UserNavMenuDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(UserNavMenuDO::getId));
}
}

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.system.enums.permission;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum MenuClientTypeEnum {
WEB(1),
APP(2);
private final Integer type;
}

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSa
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper;
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.system.enums.permission.MenuClientTypeEnum;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import com.google.common.annotations.VisibleForTesting;
@ -50,10 +51,11 @@ public class MenuServiceImpl implements MenuService {
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission",
condition = "#createReqVO.permission != null")
public Long createMenu(MenuSaveVO createReqVO) {
defaultClientType(createReqVO);
// 校验父菜单存在
validateParentMenu(createReqVO.getParentId(), null);
validateParentMenu(createReqVO.getParentId(), createReqVO.getClientType(), null);
// 校验菜单(自己)
validateMenu(createReqVO.getParentId(), createReqVO.getName(), null);
validateMenu(createReqVO.getParentId(), createReqVO.getName(), createReqVO.getClientType(), null);
// 插入数据库
MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class);
@ -67,14 +69,15 @@ public class MenuServiceImpl implements MenuService {
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理简单有效
public void updateMenu(MenuSaveVO updateReqVO) {
defaultClientType(updateReqVO);
// 校验更新的菜单是否存在
if (menuMapper.selectById(updateReqVO.getId()) == null) {
throw exception(MENU_NOT_EXISTS);
}
// 校验父菜单存在
validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId());
validateParentMenu(updateReqVO.getParentId(), updateReqVO.getClientType(), updateReqVO.getId());
// 校验菜单(自己)
validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId());
validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getClientType(), updateReqVO.getId());
// 更新到数据库
MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class);
@ -163,6 +166,7 @@ public class MenuServiceImpl implements MenuService {
@Override
public List<MenuDO> getMenuList(MenuListReqVO reqVO) {
defaultClientType(reqVO);
return menuMapper.selectList(reqVO);
}
@ -198,7 +202,7 @@ public class MenuServiceImpl implements MenuService {
* @param childId
*/
@VisibleForTesting
void validateParentMenu(Long parentId, Long childId) {
void validateParentMenu(Long parentId, Integer clientType, Long childId) {
if (parentId == null || ID_ROOT.equals(parentId)) {
return;
}
@ -216,6 +220,9 @@ public class MenuServiceImpl implements MenuService {
&& !MenuTypeEnum.MENU.getType().equals(menu.getType())) {
throw exception(MENU_PARENT_NOT_DIR_OR_MENU);
}
if (!Objects.equals(menu.getClientType(), clientType)) {
throw exception(MENU_CLIENT_TYPE_INCONSISTENT);
}
}
/**
@ -228,8 +235,8 @@ public class MenuServiceImpl implements MenuService {
* @param id
*/
@VisibleForTesting
void validateMenu(Long parentId, String name, Long id) {
MenuDO menu = menuMapper.selectByParentIdAndName(parentId, name);
void validateMenu(Long parentId, String name, Integer clientType, Long id) {
MenuDO menu = menuMapper.selectByParentIdAndNameAndClientType(parentId, name, clientType);
if (menu == null) {
return;
}
@ -250,6 +257,9 @@ public class MenuServiceImpl implements MenuService {
* @param menu
*/
private void initMenuProperty(MenuDO menu) {
if (menu.getClientType() == null) {
menu.setClientType(MenuClientTypeEnum.WEB.getType());
}
// 菜单为按钮类型时,无需 component、icon、path 属性,进行置空
if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) {
menu.setComponent("");
@ -259,4 +269,16 @@ public class MenuServiceImpl implements MenuService {
}
}
private void defaultClientType(MenuListReqVO reqVO) {
if (reqVO.getClientType() == null) {
reqVO.setClientType(MenuClientTypeEnum.WEB.getType());
}
}
private void defaultClientType(MenuSaveVO reqVO) {
if (reqVO.getClientType() == null) {
reqVO.setClientType(MenuClientTypeEnum.WEB.getType());
}
}
}

@ -33,8 +33,10 @@ import javax.annotation.Resource;
import java.util.*;
import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MENU_CLIENT_TYPE_INCONSISTENT;
/**
* Service
@ -139,6 +141,7 @@ public class PermissionServiceImpl implements PermissionService {
allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快
})
public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
validateMenuClientType(menuIds);
// 获得角色拥有菜单编号
Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
// 计算新增和删除的菜单编号
@ -159,6 +162,18 @@ public class PermissionServiceImpl implements PermissionService {
}
}
private void validateMenuClientType(Set<Long> menuIds) {
if (CollUtil.isEmpty(menuIds)) {
return;
}
List<MenuDO> menus = menuService.getMenuList(menuIds);
Set<Integer> clientTypes = convertSet(menus, MenuDO::getClientType);
clientTypes.remove(null);
if (clientTypes.size() > 1) {
throw exception(MENU_CLIENT_TYPE_INCONSISTENT);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
@Caching(evict = {

@ -0,0 +1,61 @@
package cn.iocoder.yudao.module.system.service.usernavmenu;
import java.util.*;
import cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.usernavmenu.UserNavMenuDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import javax.validation.Valid;
/**
* App Service
*
* @author
*/
public interface UserNavMenuService {
/**
* App
*
* @param createReqVO
* @return
*/
Long createUserNavMenu(@Valid UserNavMenuSaveReqVO createReqVO);
/**
* App
*
* @param updateReqVO
*/
void updateUserNavMenu(@Valid UserNavMenuSaveReqVO updateReqVO);
/**
* App
*
* @param id
*/
void deleteUserNavMenu(Long id);
/**
* App
*
* @param id
* @return App
*/
UserNavMenuDO getUserNavMenu(Long id);
/**
* App
*
* @param pageReqVO
* @return App
*/
PageResult<UserNavMenuDO> getUserNavMenuPage(UserNavMenuPageReqVO pageReqVO);
List<UserNavMenuDO> getUserNavMenuList(@Valid UserNavMenuPageReqVO listReqVO);
void updateUserNavMenuList(@Valid List<UserNavMenuSaveReqVO> updateReqVOList);
}

@ -0,0 +1,94 @@
package cn.iocoder.yudao.module.system.service.usernavmenu;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import cn.iocoder.yudao.module.system.controller.admin.usernavmenu.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.usernavmenu.UserNavMenuDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.dal.mysql.usernavmenu.UserNavMenuMapper;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* App Service
*
* @author
*/
@Service
@Validated
public class UserNavMenuServiceImpl implements UserNavMenuService {
@Resource
private UserNavMenuMapper userNavMenuMapper;
@Override
public Long createUserNavMenu(UserNavMenuSaveReqVO createReqVO) {
// 插入
UserNavMenuDO userNavMenu = BeanUtils.toBean(createReqVO, UserNavMenuDO.class);
userNavMenuMapper.insert(userNavMenu);
// 返回
return userNavMenu.getId();
}
@Override
public void updateUserNavMenu(UserNavMenuSaveReqVO updateReqVO) {
// 校验存在
validateUserNavMenuExists(updateReqVO.getId());
// 更新
UserNavMenuDO updateObj = BeanUtils.toBean(updateReqVO, UserNavMenuDO.class);
userNavMenuMapper.updateById(updateObj);
}
@Override
public void updateUserNavMenuList(List<UserNavMenuSaveReqVO> updateReqVOList) {
if (updateReqVOList == null || updateReqVOList.isEmpty()) {
return;
}
Long userId = updateReqVOList.get(0).getUserId();
for (UserNavMenuSaveReqVO updateReqVO : updateReqVOList) {
if (!Objects.equals(userId, updateReqVO.getUserId())) {
throw exception(USER_NAV_MENU_NOT_EXISTS);
}
}
userNavMenuMapper.deleteByUserId(userId);
List<UserNavMenuDO> insertList = BeanUtils.toBean(updateReqVOList, UserNavMenuDO.class);
insertList.forEach(userNavMenuMapper::insert);
}
@Override
public void deleteUserNavMenu(Long id) {
// 校验存在
validateUserNavMenuExists(id);
// 删除
userNavMenuMapper.deleteById(id);
}
private void validateUserNavMenuExists(Long id) {
if (userNavMenuMapper.selectById(id) == null) {
throw exception(USER_NAV_MENU_NOT_EXISTS);
}
}
@Override
public UserNavMenuDO getUserNavMenu(Long id) {
return userNavMenuMapper.selectById(id);
}
@Override
public List<UserNavMenuDO> getUserNavMenuList(UserNavMenuPageReqVO listReqVO) {
return userNavMenuMapper.selectList(listReqVO);
}
@Override
public PageResult<UserNavMenuDO> getUserNavMenuPage(UserNavMenuPageReqVO pageReqVO) {
return userNavMenuMapper.selectPage(pageReqVO);
}
}

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.system.dal.mysql.usernavmenu.UserNavMenuMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>
Loading…
Cancel
Save