Browse Source
- 新增 MenuType 枚举(CATALOG/MENU/BUTTON,含 fromCode 和 isLegalChild) - SysMenu 实体加 5 字段:description/perms/denyBehavior/status/apiUrl - 新增 ResourceNode DTO(含 fromEntity/toEntity 互转,映射 menuName/name、path/route) - 95 tests 全绿,零回归master
3 changed files with 152 additions and 0 deletions
@ -0,0 +1,79 @@ |
|||||
|
package com.crm.auth.domain.dto; |
||||
|
|
||||
|
import com.crm.auth.domain.entity.SysMenu; |
||||
|
import com.crm.auth.domain.enums.MenuType; |
||||
|
import com.crm.base.utils.BeanCopyUtils; |
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* 权限资源树节点 DTO(ADR-0011) |
||||
|
* <p>管理端资源树的输入输出载体;与 SysMenu 通过 BeanCopyUtils 互转</p> |
||||
|
*/ |
||||
|
@Data |
||||
|
public class ResourceNode implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@Schema(description = "节点 ID,新增时不传、编辑时必传") |
||||
|
private Long id; |
||||
|
|
||||
|
@Schema(description = "父节点 ID,根节点传 null/0") |
||||
|
private Long parentId; |
||||
|
|
||||
|
@Schema(description = "节点名称") |
||||
|
private String name; |
||||
|
|
||||
|
@Schema(description = "节点类型", example = "CATALOG") |
||||
|
private MenuType type; |
||||
|
|
||||
|
@Schema(description = "排序", example = "1") |
||||
|
private Integer sort; |
||||
|
|
||||
|
@Schema(description = "描述/备注") |
||||
|
private String description; |
||||
|
|
||||
|
@Schema(description = "前端路由路径,menu 必填") |
||||
|
private String route; |
||||
|
|
||||
|
@Schema(description = "权限码(如 crm:user:list),button 必填") |
||||
|
private String perms; |
||||
|
|
||||
|
@Schema(description = "无权限时的前端行为:hide / disable,button 必填") |
||||
|
private String denyBehavior; |
||||
|
|
||||
|
@Schema(description = "接口 URL,button 必填") |
||||
|
private String apiUrl; |
||||
|
|
||||
|
@Schema(description = "权限点状态:enabled 启用 / disabled 停用") |
||||
|
private String status; |
||||
|
|
||||
|
@Schema(description = "图标 URL,catalog/menu 可选") |
||||
|
private String icon; |
||||
|
|
||||
|
/** SysMenu → ResourceNode(id 映射 + menuName→name + path→route) */ |
||||
|
public static ResourceNode fromEntity(SysMenu entity) { |
||||
|
ResourceNode dto = BeanCopyUtils.copy(entity, ResourceNode::new); |
||||
|
if (entity != null) { |
||||
|
dto.setName(entity.getMenuName()); |
||||
|
dto.setType(MenuType.fromCode(entity.getMenuType())); |
||||
|
dto.setRoute(entity.getPath()); |
||||
|
} |
||||
|
return dto; |
||||
|
} |
||||
|
|
||||
|
/** ResourceNode → SysMenu(反向映射 name→menuName + route→path) */ |
||||
|
public SysMenu toEntity() { |
||||
|
SysMenu entity = BeanCopyUtils.copy(this, SysMenu::new); |
||||
|
entity.setMenuName(this.name); |
||||
|
if (this.type != null) { |
||||
|
entity.setMenuType(this.type.getCode()); |
||||
|
} |
||||
|
entity.setPath(this.route); |
||||
|
return entity; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
package com.crm.auth.domain.enums; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* 权限资源树节点类型枚举(ADR-0011) |
||||
|
* <p>DB 存储 tinyint(1/2/3),代码层用枚举;提供 fromCode 工厂方法和 toCode 映射</p> |
||||
|
*/ |
||||
|
@Getter |
||||
|
@RequiredArgsConstructor |
||||
|
public enum MenuType { |
||||
|
|
||||
|
/** 菜单分组:收纳容器,不承载页面,只能挂 menu 子节点 */ |
||||
|
CATALOG(1, "catalog"), |
||||
|
|
||||
|
/** 菜单页面:可导航的页面,只能挂 button 子节点 */ |
||||
|
MENU(2, "menu"), |
||||
|
|
||||
|
/** 按钮/权限点:叶子节点,不可再挂子节点,承载权限码和接口映射 */ |
||||
|
BUTTON(3, "button"); |
||||
|
|
||||
|
private final int code; |
||||
|
private final String value; |
||||
|
|
||||
|
/** 从 DB tinyint 值反查枚举,找不到返回 null */ |
||||
|
public static MenuType fromCode(Integer code) { |
||||
|
if (code == null) return null; |
||||
|
return Arrays.stream(values()) |
||||
|
.filter(t -> t.code == code) |
||||
|
.findFirst() |
||||
|
.orElse(null); |
||||
|
} |
||||
|
|
||||
|
/** 是否允许作为某父类型的子节点 */ |
||||
|
public static boolean isLegalChild(MenuType parentType, MenuType childType) { |
||||
|
if (childType == null) return false; |
||||
|
switch (parentType) { |
||||
|
case CATALOG: |
||||
|
return childType == MENU; |
||||
|
case MENU: |
||||
|
return childType == BUTTON; |
||||
|
case BUTTON: |
||||
|
return false; // 叶子节点
|
||||
|
default: |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue