diff --git a/src/main/java/com/cczsa/xinghe/codegen/controller/MenuController.java b/src/main/java/com/cczsa/xinghe/codegen/controller/MenuController.java new file mode 100644 index 0000000..1aeca8f --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/controller/MenuController.java @@ -0,0 +1,69 @@ +package com.cczsa.xinghe.codegen.controller; + +import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq; +import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes; +import com.cczsa.xinghe.codegen.service.MenuService; +import com.cczsa.xinghe.codegen.util.XResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 菜单管理 控制层。 + * + * @author xia + * @version 0.0.1 + */ +@Tag(name = "菜单管理") +@RequiredArgsConstructor +@RestController +@RequestMapping("/menu") +public class MenuController { + + private final MenuService menuService; + + @Operation(summary = "获取菜单列表", description = "获取菜单列表") + @PostMapping("/query") + public XResult> query(@RequestBody @Valid MenuQueryReq req) { + return menuService.query(req); + } + + @Operation(summary = "创建菜单", description = "创建菜单") + @PutMapping("/add") + public XResult add(@RequestBody @Valid MenuAddReq req) { + return menuService.add(req); + } + + @Operation(summary = "修改菜单", description = "修改菜单") + @PostMapping("/edit") + public XResult edit(@RequestBody @Valid MenuEditReq req) { + return menuService.edit(req); + } + + @Operation(summary = "删除菜单", description = "删除菜单") + @DeleteMapping("/delete/{id}") + public XResult delete(@PathVariable Long id) { + return menuService.delete(id); + } + + @Operation(summary = "菜单绑定权限", description = "菜单绑定权限") + @PostMapping("/bind/fun") + public XResult bindFun(@RequestBody @Valid MenuBindFunReq req) { + return menuService.bindFun(req); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/MenuBindFunEntity.java b/src/main/java/com/cczsa/xinghe/codegen/entity/MenuBindFunEntity.java new file mode 100644 index 0000000..11b8787 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/MenuBindFunEntity.java @@ -0,0 +1,50 @@ +package com.cczsa.xinghe.codegen.entity; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; + +import java.io.Serializable; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.EqualsAndHashCode; + +/** + * 菜单绑定权限 实体类。 + * + * @author My + * @since 0.0.1 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Table("cg_menu_bind_fun") +public class MenuBindFunEntity extends BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 功能ID + */ + private Long funId; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/MenuEntity.java b/src/main/java/com/cczsa/xinghe/codegen/entity/MenuEntity.java new file mode 100644 index 0000000..041864b --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/MenuEntity.java @@ -0,0 +1,82 @@ +package com.cczsa.xinghe.codegen.entity; + +import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; + +import java.io.Serializable; + +import java.io.Serial; + +import com.mybatisflex.core.keygen.KeyGenerators; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.EqualsAndHashCode; + +/** + * 菜单 实体类。 + * + * @author My + * @since 0.0.1 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Table("cg_menu") +public class MenuEntity extends BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 客户端类型:0 PC端,1 小程序端,2 H5端 + */ + private ClientTypeEnum clientType; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 路由路径 + */ + private String path; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 是否租户 + */ + private Boolean isTenant; + + /** + * 是否隐藏 + */ + private Boolean isHide; + + /** + * 排序 + */ + private Integer sortOrder; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/enums/ClientTypeEnum.java b/src/main/java/com/cczsa/xinghe/codegen/entity/enums/ClientTypeEnum.java new file mode 100644 index 0000000..0380b94 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/enums/ClientTypeEnum.java @@ -0,0 +1,36 @@ +package com.cczsa.xinghe.codegen.entity.enums; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.mybatisflex.annotation.EnumValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +/** + * 客户端类型枚举 + * + * @author My + */ +@Schema(description = "客户端类型", + example = "0", + allowableValues = {"0: PC端", "1: 小程序端", "2: H5端"}) +@Getter +public enum ClientTypeEnum { + // 客户端类型:0 PC端,1 小程序端,2 H5端 + PC(0, "PC端"), + MINI_PROGRAM(1, "小程序端"), + H5(2, "H5端"); + + private final int code; + private final String desc; + + ClientTypeEnum(int code, String desc) { + this.code = code; + this.desc = desc; + } + + @JsonValue + @EnumValue + public int getCode() { + return code; + } +} \ No newline at end of file diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuAddReq.java b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuAddReq.java new file mode 100644 index 0000000..e9dba01 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuAddReq.java @@ -0,0 +1,53 @@ +package com.cczsa.xinghe.codegen.entity.req.menu; + +import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 创建菜单 请求参数 + * + * @author xia + * @version 0.0.1 + */ +@Getter +@Setter +@Schema(description = "创建菜单-参数") +public class MenuAddReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "客户端类型不能为空") + @Schema(description = "客户端类型:0 PC端,1 小程序端,2 H5端") + private ClientTypeEnum clientType; + + @NotNull(message = "菜单名称不能为空") + @Schema(description = "菜单名称") + private String menuName; + + @Schema(description = "父菜单ID") + private Long parentId = 0L; + + @Schema(description = "路由路径") + private String path; + + @Schema(description = "菜单图标") + private String icon; + + @NotNull(message = "是否租户不能为空") + @Schema(description = "是否租户") + private Boolean isTenant; + + @Schema(description = "是否隐藏") + private Boolean isHide; + + @Schema(description = "排序") + private Integer sortOrder; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuBindFunReq.java b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuBindFunReq.java new file mode 100644 index 0000000..b739300 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuBindFunReq.java @@ -0,0 +1,33 @@ +package com.cczsa.xinghe.codegen.entity.req.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 菜单绑定权限 请求参数 + * + * @author xia + * @version 0.0.1 + */ +@Getter +@Setter +@Schema(description = "菜单绑定权限-参数") +public class MenuBindFunReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "菜单ID不能为空") + @Schema(description = "菜单ID") + private Long menuId; + + @NotNull(message = "功能ID不能为空") + @Schema(description = "功能ID") + private Long funId; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuEditReq.java b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuEditReq.java new file mode 100644 index 0000000..56f7507 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuEditReq.java @@ -0,0 +1,55 @@ +package com.cczsa.xinghe.codegen.entity.req.menu; + +import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import java.io.Serial; +import java.io.Serializable; + +/** + * 修改菜单 请求参数 + * @author xia + * @version 0.0.1 + */ +@Getter +@Setter +@Schema(description = "修改菜单-参数") +public class MenuEditReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "主键ID不能为空") + @Schema(description = "主键ID") + private Long id; + + @NotNull(message = "客户端类型不能为空") + @Schema(description = "客户端类型:0 PC端,1 小程序端,2 H5端") + private ClientTypeEnum clientType; + + @NotNull(message = "菜单名称不能为空") + @Schema(description = "菜单名称") + private String menuName; + + @Schema(description = "父菜单ID") + private Long parentId = 0L; + + @Schema(description = "路由路径") + private String path; + + @Schema(description = "菜单图标") + private String icon; + + @NotNull(message = "是否租户不能为空") + @Schema(description = "是否租户") + private Boolean isTenant; + + @Schema(description = "是否隐藏") + private Boolean isHide; + + @Schema(description = "排序") + private Integer sortOrder; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuQueryReq.java b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuQueryReq.java new file mode 100644 index 0000000..54d28be --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/req/menu/MenuQueryReq.java @@ -0,0 +1,34 @@ +package com.cczsa.xinghe.codegen.entity.req.menu; + +import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import java.io.Serial; +import java.io.Serializable; + +/** + * 获取菜单列表 请求参数 + * @author xia + * @version 0.0.1 + */ +@Getter +@Setter +@Schema(description = "获取菜单列表-参数") +public class MenuQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull( message = "客户端类型不能为空") + @Schema(description = "客户端类型:0 PC端,1 小程序端,2 H5端") + private ClientTypeEnum clientType; + + @Schema(description = "菜单名称") + private String menuName; + + @Schema(description = "父菜单ID") + private Long parentId; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/entity/res/menu/MenuQueryRes.java b/src/main/java/com/cczsa/xinghe/codegen/entity/res/menu/MenuQueryRes.java new file mode 100644 index 0000000..af92d31 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/entity/res/menu/MenuQueryRes.java @@ -0,0 +1,55 @@ +package com.cczsa.xinghe.codegen.entity.res.menu; + +import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 获取菜单列表 响应参数 + * @author xia + * @version 0.0.1 + */ +@Getter +@Setter +@Schema(description = "获取菜单列表-响应") +public class MenuQueryRes implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "客户端类型:0 PC端,1 小程序端,2 H5端") + private ClientTypeEnum clientType; + + @Schema(description = "菜单名称") + private String menuName; + + @Schema(description = "父菜单ID") + private Long parentId = 0L; + + @Schema(description = "路由路径") + private String path; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "是否租户") + private Boolean isTenant; + + @Schema(description = "是否隐藏") + private Boolean isHide; + + @Schema(description = "排序") + private Integer sortOrder; + + @Schema(description = "子菜单") + private List children; + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuBindFunMapper.java b/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuBindFunMapper.java new file mode 100644 index 0000000..fededc4 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuBindFunMapper.java @@ -0,0 +1,16 @@ +package com.cczsa.xinghe.codegen.mapper; + +import org.apache.ibatis.annotations.Mapper; +import com.mybatisflex.core.BaseMapper; +import com.cczsa.xinghe.codegen.entity.MenuBindFunEntity; + +/** + * 菜单绑定权限 映射层。 + * + * @author My + * @since 0.0.1 + */ +@Mapper +public interface MenuBindFunMapper extends BaseMapper { + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuMapper.java b/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuMapper.java new file mode 100644 index 0000000..071772c --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/mapper/MenuMapper.java @@ -0,0 +1,16 @@ +package com.cczsa.xinghe.codegen.mapper; + +import org.apache.ibatis.annotations.Mapper; +import com.mybatisflex.core.BaseMapper; +import com.cczsa.xinghe.codegen.entity.MenuEntity; + +/** + * 菜单 映射层。 + * + * @author My + * @since 0.0.1 + */ +@Mapper +public interface MenuMapper extends BaseMapper { + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuBindFunDef.java b/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuBindFunDef.java new file mode 100644 index 0000000..aba10eb --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuBindFunDef.java @@ -0,0 +1,62 @@ +package com.cczsa.xinghe.codegen.mapper.def; + +import com.mybatisflex.core.query.QueryColumn; +import com.mybatisflex.core.table.TableDef; + +import java.io.Serial; + +/** + * 菜单绑定权限 表定义层。 + * + * @author My + * @since 0.0.1 + */ +public class MenuBindFunDef extends TableDef { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单绑定权限 + */ + public static final MenuBindFunDef MENU_BIND_FUN_ENTITY = new MenuBindFunDef(); + + /** + * 主键ID + */ + public final QueryColumn ID = new QueryColumn(this, "id"); + + /** + * 功能ID + */ + public final QueryColumn FUN_ID = new QueryColumn(this, "fun_id"); + + /** + * 菜单ID + */ + public final QueryColumn MENU_ID = new QueryColumn(this, "menu_id"); + + /** + * 所有字段。 + */ + public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*"); + + /** + * 默认字段,不包含逻辑删除或者 large 等字段。 + */ + public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, MENU_ID, FUN_ID}; + + public MenuBindFunDef() { + super("", "cg_menu_bind_fun"); + } + + private MenuBindFunDef(String schema, String name, String alisa) { + super(schema, name, alisa); + } + + public MenuBindFunDef as(String alias) { + String key = getNameWithSchema() + "." + alias; + return getCache(key, k -> new MenuBindFunDef("", "cg_menu_bind_fun", alias)); + } + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuDef.java b/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuDef.java new file mode 100644 index 0000000..bd8fbc2 --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/mapper/def/MenuDef.java @@ -0,0 +1,90 @@ +package com.cczsa.xinghe.codegen.mapper.def; + +import com.mybatisflex.core.query.QueryColumn; +import com.mybatisflex.core.table.TableDef; + +import java.io.Serial; + +/** + * 菜单 表定义层。 + * + * @author My + * @since 0.0.1 + */ +public class MenuDef extends TableDef { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单 + */ + public static final MenuDef MENU_ENTITY = new MenuDef(); + + /** + * 主键ID + */ + public final QueryColumn ID = new QueryColumn(this, "id"); + + /** + * 菜单图标 + */ + public final QueryColumn ICON = new QueryColumn(this, "icon"); + + /** + * 路由路径 + */ + public final QueryColumn PATH = new QueryColumn(this, "path"); + + /** + * 是否隐藏 + */ + public final QueryColumn IS_HIDE = new QueryColumn(this, "is_hide"); + + /** + * 是否租户 + */ + public final QueryColumn IS_TENANT = new QueryColumn(this, "is_tenant"); + + /** + * 菜单名称 + */ + public final QueryColumn MENU_NAME = new QueryColumn(this, "menu_name"); + + /** + * 父菜单ID + */ + public final QueryColumn PARENT_ID = new QueryColumn(this, "parent_id"); + + + public final QueryColumn SORT_ORDER = new QueryColumn(this, "sort_order"); + + /** + * 客户端类型:0 PC端,1 小程序端,2 H5端 + */ + public final QueryColumn CLIENT_TYPE = new QueryColumn(this, "client_type"); + + /** + * 所有字段。 + */ + public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*"); + + /** + * 默认字段,不包含逻辑删除或者 large 等字段。 + */ + public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, CLIENT_TYPE, MENU_NAME, PARENT_ID, PATH, ICON, IS_TENANT, IS_HIDE, SORT_ORDER}; + + public MenuDef() { + super("", "cg_menu"); + } + + private MenuDef(String schema, String name, String alisa) { + super(schema, name, alisa); + } + + public MenuDef as(String alias) { + String key = getNameWithSchema() + "." + alias; + return getCache(key, k -> new MenuDef("", "cg_menu", alias)); + } + +} diff --git a/src/main/java/com/cczsa/xinghe/codegen/service/MenuService.java b/src/main/java/com/cczsa/xinghe/codegen/service/MenuService.java new file mode 100644 index 0000000..3039cde --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/service/MenuService.java @@ -0,0 +1,46 @@ +package com.cczsa.xinghe.codegen.service; + +import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq; +import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes; +import com.cczsa.xinghe.codegen.util.XResult; + +import java.util.List; + +/** + * 菜单管理 服务层接口。 + * + * @author xia + * @version 0.0.1 + */ +public interface MenuService { + + /** + * 获取菜单列表 + */ + XResult> query(MenuQueryReq req); + + /** + * 创建菜单 + */ + XResult add(MenuAddReq req); + + /** + * 修改菜单 + */ + XResult edit(MenuEditReq req); + + /** + * 删除菜单 + */ + XResult delete(Long id); + + /** + * 菜单绑定权限 + */ + XResult bindFun(MenuBindFunReq req); + + +} \ No newline at end of file diff --git a/src/main/java/com/cczsa/xinghe/codegen/service/impl/MenuServiceImpl.java b/src/main/java/com/cczsa/xinghe/codegen/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..908980f --- /dev/null +++ b/src/main/java/com/cczsa/xinghe/codegen/service/impl/MenuServiceImpl.java @@ -0,0 +1,241 @@ +package com.cczsa.xinghe.codegen.service.impl; + +import com.cczsa.xinghe.codegen.entity.FunItemEntity; +import com.cczsa.xinghe.codegen.entity.FunOperationEntity; +import com.cczsa.xinghe.codegen.entity.MenuBindFunEntity; +import com.cczsa.xinghe.codegen.entity.MenuEntity; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq; +import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq; +import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes; +import com.cczsa.xinghe.codegen.mapper.FunItemMapper; +import com.cczsa.xinghe.codegen.mapper.FunOperationMapper; +import com.cczsa.xinghe.codegen.mapper.MenuBindFunMapper; +import com.cczsa.xinghe.codegen.mapper.MenuMapper; +import com.cczsa.xinghe.codegen.mapper.def.MenuBindFunDef; +import com.cczsa.xinghe.codegen.mapper.def.MenuDef; +import com.cczsa.xinghe.codegen.service.MenuService; +import com.cczsa.xinghe.codegen.util.XResult; +import com.github.xiaoymin.knife4j.core.util.StrUtil; +import com.mybatisflex.core.query.QueryWrapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 菜单管理 服务层实现。 + * + * @author xia + * @version 0.0.1 + */ +@Service +@RequiredArgsConstructor +public class MenuServiceImpl implements MenuService { + + private final MenuMapper menuMapper; + private final MenuBindFunMapper menuBindFunMapper; + private final FunOperationMapper funOperationMapper; + private final FunItemMapper funItemMapper; + + + /** + * 获取菜单列表 + */ + @Override + public XResult> query(MenuQueryReq req) { + MenuDef menuDef = MenuDef.MENU_ENTITY; + QueryWrapper query = new QueryWrapper(); + query.select(menuDef.ALL_COLUMNS) + .from(menuDef) + .eq(MenuEntity::getClientType, req.getClientType()) + .like(MenuEntity::getMenuName, req.getMenuName(), StrUtil.isNotBlank(req.getMenuName())) + .eq(MenuEntity::getParentId, req.getParentId(), req.getParentId() != null) + .orderBy(MenuEntity::getSortOrder, false); + List menuEntities = menuMapper.selectListByQueryAs(query, MenuQueryRes.class); + // 构建树形结构 + List treeList = buildMenuTree(menuEntities); + return XResult.ok(treeList); + } + + /** + * 构建树形结构 + */ + private List buildMenuTree(List menuEntities) { + // 创建一个Map用于快速查找分组 + Map menuMap = new HashMap<>(); + for (MenuQueryRes menu : menuEntities) { + menuMap.put(menu.getId(), menu); + } + // 构建树形结构 + List rootMenuList = new ArrayList<>(); + for (MenuQueryRes menu : menuEntities) { + Long parentId = menu.getParentId(); + if (parentId == 0) { + // 根分组 + rootMenuList.add(menu); + } else { + // 如果父节点在结果中,则挂到父节点下 + MenuQueryRes parentMenu = menuMap.get(parentId); + if (parentMenu != null) { + if (parentMenu.getChildren() == null) { + parentMenu.setChildren(new ArrayList<>()); + } + parentMenu.getChildren().add(menu); + } else { + // 如果父节点不在结果中,则将该节点作为根节点处理 + rootMenuList.add(menu); + } + } + } + return rootMenuList; + } + + /** + * 创建菜单 + */ + @Override + public XResult add(MenuAddReq req) { + // 获取最大ID + MenuDef menuDef = MenuDef.MENU_ENTITY; + QueryWrapper queryId = new QueryWrapper(); + queryId.select(menuDef.ID) + .from(menuDef) + .orderBy(MenuEntity::getId, false); + Long maxId = menuMapper.selectOneByQueryAs(queryId, Long.class); + if (maxId == null) { + maxId = 10000L; + } else { + maxId++; + } + QueryWrapper query = new QueryWrapper(); + query.select(menuDef.ID) + .from(menuDef) + .eq(MenuEntity::getParentId, req.getParentId()) + .eq(MenuEntity::getMenuName, req.getMenuName()); + long count = menuMapper.selectCountByQuery(query); + if (count > 0) { + return XResult.failed("菜单已存在"); + } + MenuEntity menuEntity = new MenuEntity(); + menuEntity.setId(maxId); + BeanUtils.copyProperties(req, menuEntity); + menuMapper.insertSelective(menuEntity); + return XResult.ok(); + } + + /** + * 修改菜单 + */ + @Override + public XResult edit(MenuEditReq req) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq(MenuEntity::getId, req.getId()); + MenuEntity menuEntity = menuMapper.selectOneByQuery(queryWrapper); + if (menuEntity == null) { + return XResult.failed("菜单不存在"); + } + MenuDef menuDef = MenuDef.MENU_ENTITY; + QueryWrapper queryCount = new QueryWrapper(); + queryCount.select(menuDef.ID) + .from(menuDef) + .eq(MenuEntity::getParentId, req.getParentId()) + .eq(MenuEntity::getMenuName, req.getMenuName()) + .ne(MenuEntity::getId, req.getId()); + long count = menuMapper.selectCountByQuery(queryCount); + if (count > 0) { + return XResult.failed("菜单已存在"); + } + BeanUtils.copyProperties(req, menuEntity); + menuMapper.update(menuEntity); + return XResult.ok(); + } + + /** + * 删除菜单 + */ + @Transactional + @Override + public XResult delete(Long id) { + // 是否有子菜单 + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq(MenuEntity::getParentId, id); + long count = menuMapper.selectCountByQuery(queryWrapper); + if (count > 0) { + return XResult.failed("请先删除子菜单"); + } + QueryWrapper deleteMenu = new QueryWrapper(); + deleteMenu.eq(MenuEntity::getId, id); + menuMapper.deleteByQuery(deleteMenu); + // 删除菜单绑定的权限 + QueryWrapper deleteMenuBindFun = new QueryWrapper(); + deleteMenuBindFun.eq(MenuBindFunEntity::getMenuId, id); + menuBindFunMapper.deleteByQuery(deleteMenuBindFun); + return XResult.ok(); + } + + /** + * 菜单绑定权限 + */ + @Transactional + @Override + public XResult bindFun(MenuBindFunReq req) { + // 获取菜单 + QueryWrapper queryMenu = new QueryWrapper(); + queryMenu.eq(MenuEntity::getId, req.getMenuId()); + MenuEntity menuEntity = menuMapper.selectOneByQuery(queryMenu); + if (menuEntity == null) { + return XResult.failed("菜单不存在"); + } + // 获取操作 + QueryWrapper queryFun = new QueryWrapper(); + queryFun.eq(FunOperationEntity::getId, req.getFunId()); + FunOperationEntity funOperationEntity = funOperationMapper.selectOneByQuery(queryFun); + if (funOperationEntity == null) { + return XResult.failed("权限不存在"); + } + // 获取功能 + QueryWrapper queryItem = new QueryWrapper(); + queryItem.eq(FunItemEntity::getId, funOperationEntity.getItemId()); + FunItemEntity funItemEntity = funItemMapper.selectOneByQuery(queryItem); + if (funItemEntity == null) { + return XResult.failed("功能不存在"); + } + Boolean menuIsTenant = menuEntity.getIsTenant(); + Boolean itemIsTenant = funItemEntity.getIsTenant(); + if (!menuIsTenant.equals(itemIsTenant)) { + return XResult.failed("菜单和权限是否租户不一致"); + } + // 删除旧绑定 + QueryWrapper deleteMenuBindFun = new QueryWrapper(); + deleteMenuBindFun.eq(MenuBindFunEntity::getMenuId, req.getMenuId()); + deleteMenuBindFun.eq(MenuBindFunEntity::getFunId, req.getFunId()); + menuBindFunMapper.deleteByQuery(deleteMenuBindFun); + // 获取最大ID + MenuBindFunDef menuBindFunDef = MenuBindFunDef.MENU_BIND_FUN_ENTITY; + QueryWrapper queryId = new QueryWrapper(); + queryId.select(menuBindFunDef.ID) + .from(menuBindFunDef) + .orderBy(MenuBindFunEntity::getId, false); + Long maxId = menuBindFunMapper.selectOneByQueryAs(queryId, Long.class); + if (maxId == null) { + maxId = 10000L; + } else { + maxId++; + } + // 新增绑定 + MenuBindFunEntity menuBindFunEntity = new MenuBindFunEntity(); + menuBindFunEntity.setId(maxId); + menuBindFunEntity.setMenuId(req.getMenuId()); + menuBindFunEntity.setFunId(req.getFunId()); + menuBindFunMapper.insertSelective(menuBindFunEntity); + return XResult.ok(); + } + +} \ No newline at end of file