Browse Source

add:中台增加权限管理(权限(菜单)管理crud)

lyx 5 days ago
parent
commit
1558dc8b52

+ 108 - 0
alien-entity/src/main/java/shop/alien/entity/store/LifeSysMenu.java

@@ -0,0 +1,108 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 菜单权限表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@TableName("life_sys_menu")
+@ApiModel(value = "LifeSysMenu对象", description = "菜单权限表")
+public class LifeSysMenu {
+
+    @ApiModelProperty(value = "菜单ID")
+    @TableId(value = "menu_id", type = IdType.AUTO)
+    private Long menuId;
+
+    @ApiModelProperty(value = "菜单名称")
+    @TableField("menu_name")
+    private String menuName;
+
+    @ApiModelProperty(value = "父菜单ID(0表示根菜单)")
+    @TableField("parent_id")
+    private Long parentId;
+
+    @ApiModelProperty(value = "菜单类型(M目录 C菜单 F按钮)")
+    @TableField("menu_type")
+    private String menuType;
+
+    @ApiModelProperty(value = "显示顺序")
+    @TableField("menu_sort")
+    private Integer menuSort;
+
+    @ApiModelProperty(value = "路由地址")
+    @TableField("path")
+    private String path;
+
+    @ApiModelProperty(value = "组件路径")
+    @TableField("component")
+    private String component;
+
+    @ApiModelProperty(value = "权限标识(如:sys:user:list)")
+    @TableField("perms")
+    private String perms;
+
+    @ApiModelProperty(value = "菜单图标")
+    @TableField("icon")
+    private String icon;
+
+    @ApiModelProperty(value = "菜单状态(0正常 1停用)")
+    @TableField("status")
+    private String status;
+
+    @ApiModelProperty(value = "是否显示(0显示 1隐藏)")
+    @TableField("visible")
+    private String visible;
+
+    @ApiModelProperty(value = "是否为外链(0是 1否)")
+    @TableField("is_frame")
+    private String isFrame;
+
+    @ApiModelProperty(value = "是否缓存(0缓存 1不缓存)")
+    @TableField("is_cache")
+    private String isCache;
+
+    @ApiModelProperty(value = "删除标志(0存在 2删除)")
+    @TableField("del_flag")
+    @TableLogic(value = "0", delval = "2")
+    private String delFlag;
+
+    @ApiModelProperty(value = "创建者")
+    @TableField("create_by")
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "更新者")
+    @TableField("update_by")
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "备注")
+    @TableField("remark")
+    private String remark;
+
+    @ApiModelProperty(value = "子菜单列表(用于树形结构)")
+    @TableField(exist = false)
+    private List<LifeSysMenu> children;
+}
+

+ 16 - 0
alien-entity/src/main/java/shop/alien/mapper/LifeSysMenuMapper.java

@@ -0,0 +1,16 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.LifeSysMenu;
+
+/**
+ * 菜单权限表 Mapper 接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Mapper
+public interface LifeSysMenuMapper extends BaseMapper<LifeSysMenu> {
+}
+

+ 36 - 0
alien-entity/src/main/resources/mapper/LifeSysMenuMapper.xml

@@ -0,0 +1,36 @@
+<?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="shop.alien.mapper.LifeSysMenuMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="shop.alien.entity.store.LifeSysMenu">
+        <id column="menu_id" property="menuId" />
+        <result column="menu_name" property="menuName" />
+        <result column="parent_id" property="parentId" />
+        <result column="menu_type" property="menuType" />
+        <result column="menu_sort" property="menuSort" />
+        <result column="path" property="path" />
+        <result column="component" property="component" />
+        <result column="perms" property="perms" />
+        <result column="icon" property="icon" />
+        <result column="status" property="status" />
+        <result column="visible" property="visible" />
+        <result column="is_frame" property="isFrame" />
+        <result column="is_cache" property="isCache" />
+        <result column="del_flag" property="delFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="created_time" property="createdTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="remark" property="remark" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        menu_id, menu_name, parent_id, menu_type, menu_sort, path, component, perms, icon,
+        status, visible, is_frame, is_cache, del_flag, create_by, created_time, update_by,
+        updated_time, remark
+    </sql>
+
+</mapper>
+

+ 123 - 0
alien-store/src/main/java/shop/alien/store/controller/LifeSysMenuController.java

@@ -0,0 +1,123 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.LifeSysMenu;
+import shop.alien.store.service.LifeSysMenuService;
+
+import java.util.List;
+
+/**
+ * 菜单权限表 前端控制器
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"数据中台-菜单管理"})
+@ApiSort(3)
+@CrossOrigin
+@RestController
+@RequestMapping("/sys/menu")
+@RequiredArgsConstructor
+public class LifeSysMenuController {
+
+    private final LifeSysMenuService lifeSysMenuService;
+
+    @ApiOperation("新增菜单")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "menuName", value = "菜单名称", dataType = "String", paramType = "body", required = true),
+            @ApiImplicitParam(name = "parentId", value = "父菜单ID(0表示根菜单)", dataType = "Long", paramType = "body"),
+            @ApiImplicitParam(name = "menuType", value = "菜单类型(M目录 C菜单 F按钮)", dataType = "String", paramType = "body", required = true),
+            @ApiImplicitParam(name = "menuSort", value = "显示顺序", dataType = "Integer", paramType = "body"),
+            @ApiImplicitParam(name = "path", value = "路由地址", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "component", value = "组件路径", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "perms", value = "权限标识(如:sys:user:list)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "icon", value = "菜单图标", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "status", value = "菜单状态(0正常 1停用)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "visible", value = "是否显示(0显示 1隐藏)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "isFrame", value = "是否为外链(0是 1否)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "isCache", value = "是否缓存(0缓存 1不缓存)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "remark", value = "备注", dataType = "String", paramType = "body"),
+    })
+    @PostMapping(value = "/addMenu")
+    public R<LifeSysMenu> addMenu(@RequestBody LifeSysMenu menu) {
+        log.info("LifeSysMenuController.addMenu => menuName={}, parentId={}, menuType={}, menuSort={}, path={}, component={}, perms={}, icon={}, status={}, visible={}, isFrame={}, isCache={}, remark={}",
+                menu.getMenuName(), menu.getParentId(), menu.getMenuType(), menu.getMenuSort(),
+                menu.getPath(), menu.getComponent(), menu.getPerms(), menu.getIcon(),
+                menu.getStatus(), menu.getVisible(), menu.getIsFrame(), menu.getIsCache(), menu.getRemark());
+        return lifeSysMenuService.addMenu(menu);
+    }
+
+    @ApiOperation("编辑菜单")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "menuId", value = "菜单ID", dataType = "Long", paramType = "body", required = true),
+            @ApiImplicitParam(name = "menuName", value = "菜单名称", dataType = "String", paramType = "body", required = true),
+            @ApiImplicitParam(name = "menuType", value = "菜单类型(M目录 C菜单 F按钮)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "menuSort", value = "显示顺序", dataType = "Integer", paramType = "body"),
+            @ApiImplicitParam(name = "path", value = "路由地址", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "component", value = "组件路径", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "perms", value = "权限标识(如:sys:user:list)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "icon", value = "菜单图标", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "status", value = "菜单状态(0正常 1停用)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "visible", value = "是否显示(0显示 1隐藏)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "isFrame", value = "是否为外链(0是 1否)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "isCache", value = "是否缓存(0缓存 1不缓存)", dataType = "String", paramType = "body"),
+            @ApiImplicitParam(name = "remark", value = "备注", dataType = "String", paramType = "body"),
+    })
+    @PostMapping(value = "/updateMenu")
+    public R<LifeSysMenu> updateMenu(@RequestBody LifeSysMenu menu) {
+        log.info("LifeSysMenuController.updateMenu => menuId={}, menuName={}, menuType={}, menuSort={}, path={}, component={}, perms={}, icon={}, status={}, visible={}, isFrame={}, isCache={}, remark={}",
+                menu.getMenuId(), menu.getMenuName(), menu.getMenuType(), menu.getMenuSort(),
+                menu.getPath(), menu.getComponent(), menu.getPerms(), menu.getIcon(),
+                menu.getStatus(), menu.getVisible(), menu.getIsFrame(), menu.getIsCache(), menu.getRemark());
+        return lifeSysMenuService.updateMenu(menu);
+    }
+
+    @ApiOperation("删除菜单")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "menuId", value = "菜单ID", dataType = "Long", paramType = "query", required = true),
+    })
+    @DeleteMapping(value = "/deleteMenu")
+    public R<Boolean> deleteMenu(@RequestParam Long menuId) {
+        log.info("LifeSysMenuController.deleteMenu => menuId={}", menuId);
+        return lifeSysMenuService.deleteMenu(menuId);
+    }
+
+    @ApiOperation("根据ID查询菜单")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "menuId", value = "菜单ID", dataType = "Long", paramType = "query", required = true),
+    })
+    @GetMapping(value = "/getMenuById")
+    public R<LifeSysMenu> getMenuById(@RequestParam Long menuId) {
+        log.info("LifeSysMenuController.getMenuById => menuId={}", menuId);
+        return lifeSysMenuService.getMenuById(menuId);
+    }
+
+    @ApiOperation("查询菜单树形结构")
+    @ApiOperationSupport(order = 5)
+    @GetMapping(value = "/getMenuTree")
+    public R<List<LifeSysMenu>> getMenuTree() {
+        log.info("LifeSysMenuController.getMenuTree");
+        return lifeSysMenuService.getMenuTree();
+    }
+
+    @ApiOperation("根据父菜单ID查询子菜单列表")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "parentId", value = "父菜单ID(0表示根菜单,为空时默认查询根菜单)", dataType = "Long", paramType = "query", required = false),
+    })
+    @GetMapping(value = "/getMenuListByParentId")
+    public R<List<LifeSysMenu>> getMenuListByParentId(@RequestParam(required = false) Long parentId) {
+        log.info("LifeSysMenuController.getMenuListByParentId => parentId={}", parentId);
+        return lifeSysMenuService.getMenuListByParentId(parentId);
+    }
+}
+

+ 63 - 0
alien-store/src/main/java/shop/alien/store/service/LifeSysMenuService.java

@@ -0,0 +1,63 @@
+package shop.alien.store.service;
+
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.LifeSysMenu;
+
+import java.util.List;
+
+/**
+ * 菜单权限表 服务接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface LifeSysMenuService {
+
+    /**
+     * 新增菜单
+     *
+     * @param menu 菜单信息
+     * @return R<LifeSysMenu>
+     */
+    R<LifeSysMenu> addMenu(LifeSysMenu menu);
+
+    /**
+     * 更新菜单
+     *
+     * @param menu 菜单信息
+     * @return R<LifeSysMenu>
+     */
+    R<LifeSysMenu> updateMenu(LifeSysMenu menu);
+
+    /**
+     * 删除菜单
+     *
+     * @param menuId 菜单ID
+     * @return R<Boolean>
+     */
+    R<Boolean> deleteMenu(Long menuId);
+
+    /**
+     * 根据ID查询菜单
+     *
+     * @param menuId 菜单ID
+     * @return R<LifeSysMenu>
+     */
+    R<LifeSysMenu> getMenuById(Long menuId);
+
+    /**
+     * 查询菜单列表(树形结构)
+     *
+     * @return R<List<LifeSysMenu>>
+     */
+    R<List<LifeSysMenu>> getMenuTree();
+
+    /**
+     * 根据父菜单ID查询子菜单列表
+     *
+     * @param parentId 父菜单ID
+     * @return R<List<LifeSysMenu>>
+     */
+    R<List<LifeSysMenu>> getMenuListByParentId(Long parentId);
+}
+

+ 347 - 0
alien-store/src/main/java/shop/alien/store/service/impl/LifeSysMenuServiceImpl.java

@@ -0,0 +1,347 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.LifeSysMenu;
+import shop.alien.mapper.LifeSysMenuMapper;
+import shop.alien.store.service.LifeSysMenuService;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 菜单权限表 服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class LifeSysMenuServiceImpl implements LifeSysMenuService {
+
+    private final LifeSysMenuMapper lifeSysMenuMapper;
+
+    @Override
+    public R<LifeSysMenu> addMenu(LifeSysMenu menu) {
+        log.info("LifeSysMenuServiceImpl.addMenu?menu={}", menu);
+
+        // 参数校验
+        if (menu == null) {
+            log.warn("新增菜单失败:参数为空");
+            return R.fail("参数不能为空");
+        }
+
+        // 校验必填字段:菜单名称
+        if (!StringUtils.hasText(menu.getMenuName())) {
+            return R.fail("菜单名称不能为空");
+        }
+
+        // 校验必填字段:菜单类型
+        if (!StringUtils.hasText(menu.getMenuType())) {
+            return R.fail("菜单类型不能为空");
+        }
+
+        // 校验菜单名称是否已存在(同一父菜单下不能有重名)
+        QueryWrapper<LifeSysMenu> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("menu_name", menu.getMenuName());
+        queryWrapper.eq("del_flag", "0"); // 未删除的菜单
+        Long parentId = menu.getParentId() != null ? menu.getParentId() : 0L;
+        queryWrapper.eq("parent_id", parentId);
+        LifeSysMenu existingMenu = lifeSysMenuMapper.selectOne(queryWrapper);
+        if (existingMenu != null) {
+            return R.fail("该菜单名称已存在,请更换其他名称");
+        }
+
+        // 如果指定了父菜单,校验父菜单是否存在
+        if (menu.getParentId() != null && menu.getParentId() != 0) {
+            LifeSysMenu parentMenu = lifeSysMenuMapper.selectById(menu.getParentId());
+            if (parentMenu == null || !"0".equals(parentMenu.getDelFlag())) {
+                return R.fail("父菜单不存在或已被删除");
+            }
+        }
+
+        // 设置默认值
+        if (menu.getParentId() == null) {
+            menu.setParentId(0L);
+        }
+        if (menu.getMenuSort() == null) {
+            menu.setMenuSort(0);
+        }
+        if (!StringUtils.hasText(menu.getStatus())) {
+            menu.setStatus("0");
+        }
+        if (!StringUtils.hasText(menu.getVisible())) {
+            menu.setVisible("0");
+        }
+        if (!StringUtils.hasText(menu.getIsFrame())) {
+            menu.setIsFrame("1");
+        }
+        if (!StringUtils.hasText(menu.getIsCache())) {
+            menu.setIsCache("0");
+        }
+        if (!StringUtils.hasText(menu.getIcon())) {
+            menu.setIcon("#");
+        }
+        menu.setDelFlag("0"); // 未删除
+
+        // 保存菜单
+        int result = lifeSysMenuMapper.insert(menu);
+        if (result > 0) {
+            log.info("新增菜单成功,菜单ID={}", menu.getMenuId());
+            return R.data(menu, "新增菜单成功");
+        }
+        return R.fail("新增菜单失败,请稍后重试");
+    }
+
+    @Override
+    public R<LifeSysMenu> updateMenu(LifeSysMenu menu) {
+        log.info("LifeSysMenuServiceImpl.updateMenu?menu={}", menu);
+
+        // 参数校验
+        if (menu == null) {
+            log.warn("编辑菜单失败:参数为空");
+            return R.fail("参数不能为空");
+        }
+
+        // 校验必填字段:菜单ID
+        if (menu.getMenuId() == null) {
+            return R.fail("菜单ID不能为空");
+        }
+
+        // 校验必填字段:菜单名称
+        if (!StringUtils.hasText(menu.getMenuName())) {
+            return R.fail("菜单名称不能为空");
+        }
+
+        // 查询菜单是否存在
+        LifeSysMenu existingMenu = lifeSysMenuMapper.selectById(menu.getMenuId());
+        if (existingMenu == null) {
+            return R.fail("菜单不存在");
+        }
+
+        // 检查是否已被删除
+        if (!"0".equals(existingMenu.getDelFlag())) {
+            return R.fail("该菜单已被删除");
+        }
+
+        // 如果菜单名称有变化,校验新名称是否与其他菜单重复(同一父菜单下不能有重名)
+        if (!menu.getMenuName().equals(existingMenu.getMenuName())) {
+            QueryWrapper<LifeSysMenu> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("menu_name", menu.getMenuName());
+            queryWrapper.eq("del_flag", "0"); // 未删除的菜单
+            queryWrapper.ne("menu_id", menu.getMenuId()); // 排除当前菜单
+            Long parentId = existingMenu.getParentId() != null ? existingMenu.getParentId() : 0L;
+            queryWrapper.eq("parent_id", parentId);
+            LifeSysMenu duplicateMenu = lifeSysMenuMapper.selectOne(queryWrapper);
+            if (duplicateMenu != null) {
+                return R.fail("该菜单名称已存在,请更换其他名称");
+            }
+        }
+
+        // 更新菜单信息
+        existingMenu.setMenuName(menu.getMenuName());
+        existingMenu.setMenuType(menu.getMenuType());
+        existingMenu.setMenuSort(menu.getMenuSort() != null ? menu.getMenuSort() : existingMenu.getMenuSort());
+        existingMenu.setPath(menu.getPath());
+        existingMenu.setComponent(menu.getComponent());
+        existingMenu.setPerms(menu.getPerms());
+        existingMenu.setIcon(menu.getIcon() != null ? menu.getIcon() : existingMenu.getIcon());
+        existingMenu.setStatus(menu.getStatus() != null ? menu.getStatus() : existingMenu.getStatus());
+        existingMenu.setVisible(menu.getVisible() != null ? menu.getVisible() : existingMenu.getVisible());
+        existingMenu.setIsFrame(menu.getIsFrame() != null ? menu.getIsFrame() : existingMenu.getIsFrame());
+        existingMenu.setIsCache(menu.getIsCache() != null ? menu.getIsCache() : existingMenu.getIsCache());
+        existingMenu.setRemark(menu.getRemark());
+
+        // 保存更新
+        int result = lifeSysMenuMapper.updateById(existingMenu);
+        if (result > 0) {
+            log.info("编辑菜单成功,菜单ID={}, 菜单名称={}", existingMenu.getMenuId(), existingMenu.getMenuName());
+            return R.data(existingMenu, "编辑菜单成功");
+        }
+        return R.fail("编辑菜单失败,请稍后重试");
+    }
+
+    @Override
+    public R<Boolean> deleteMenu(Long menuId) {
+        log.info("LifeSysMenuServiceImpl.deleteMenu?menuId={}", menuId);
+
+        // 参数校验
+        if (menuId == null) {
+            log.warn("删除菜单失败:菜单ID为空");
+            return R.fail("菜单ID不能为空");
+        }
+
+        // 查询菜单信息
+        LifeSysMenu menu = lifeSysMenuMapper.selectById(menuId);
+        if (menu == null) {
+            return R.fail("菜单不存在");
+        }
+
+        // 检查是否已被删除
+        if (!"0".equals(menu.getDelFlag())) {
+            return R.fail("该菜单已被删除");
+        }
+
+        // 检查是否有子菜单(未删除的子菜单)
+        QueryWrapper<LifeSysMenu> childQueryWrapper = new QueryWrapper<>();
+        childQueryWrapper.eq("parent_id", menuId);
+        childQueryWrapper.eq("del_flag", "0"); // 未删除的子菜单
+        Integer childCount = lifeSysMenuMapper.selectCount(childQueryWrapper);
+
+        if (childCount != null && childCount > 0) {
+            log.warn("删除菜单失败:该菜单下存在{}个子菜单,不允许删除", childCount);
+            return R.fail("该菜单下存在子菜单,请先删除子菜单后再删除");
+        }
+
+        try {
+            // 执行逻辑删除(设置 del_flag = "2")
+            LambdaUpdateWrapper<LifeSysMenu> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(LifeSysMenu::getMenuId, menuId)
+                    .set(LifeSysMenu::getDelFlag, "2");
+
+            int result = lifeSysMenuMapper.update(null, updateWrapper);
+
+            if (result > 0) {
+                log.info("删除菜单成功,菜单ID={}, 菜单名称={}", menuId, menu.getMenuName());
+                return R.success("删除菜单成功");
+            } else {
+                return R.fail("删除菜单失败");
+            }
+        } catch (Exception e) {
+            log.error("删除菜单失败,菜单ID={}", menuId, e);
+            return R.fail("删除菜单失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<LifeSysMenu> getMenuById(Long menuId) {
+        log.info("LifeSysMenuServiceImpl.getMenuById?menuId={}", menuId);
+
+        // 参数校验
+        if (menuId == null) {
+            log.warn("查询菜单失败:菜单ID为空");
+            return R.fail("菜单ID不能为空");
+        }
+
+        // 查询菜单
+        LifeSysMenu menu = lifeSysMenuMapper.selectById(menuId);
+        if (menu == null) {
+            return R.fail("菜单不存在");
+        }
+
+        // 检查是否已被删除
+        if (!"0".equals(menu.getDelFlag())) {
+            return R.fail("该菜单已被删除");
+        }
+
+        return R.data(menu, "查询成功");
+    }
+
+    @Override
+    public R<List<LifeSysMenu>> getMenuTree() {
+        log.info("LifeSysMenuServiceImpl.getMenuTree");
+
+        try {
+            // 查询所有未删除的菜单
+            QueryWrapper<LifeSysMenu> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("del_flag", "0"); // 只查询未删除的菜单
+            queryWrapper.orderByAsc("menu_sort"); // 按排序值升序排列
+            List<LifeSysMenu> allMenus = lifeSysMenuMapper.selectList(queryWrapper);
+
+            if (allMenus == null || allMenus.isEmpty()) {
+                return R.data(new ArrayList<>(), "查询成功");
+            }
+
+            // 构建树形结构
+            List<LifeSysMenu> treeList = buildMenuTree(allMenus);
+
+            log.info("查询菜单树成功,菜单数量={}", allMenus.size());
+            return R.data(treeList, "查询成功");
+        } catch (Exception e) {
+            log.error("查询菜单树失败", e);
+            return R.fail("查询菜单树失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public R<List<LifeSysMenu>> getMenuListByParentId(Long parentId) {
+        log.info("LifeSysMenuServiceImpl.getMenuListByParentId?parentId={}", parentId);
+
+        try {
+            QueryWrapper<LifeSysMenu> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("del_flag", "0"); // 只查询未删除的菜单
+            if (parentId != null) {
+                queryWrapper.eq("parent_id", parentId);
+            } else {
+                queryWrapper.eq("parent_id", 0);
+            }
+            queryWrapper.orderByAsc("menu_sort"); // 按排序值升序排列
+            List<LifeSysMenu> menuList = lifeSysMenuMapper.selectList(queryWrapper);
+
+            log.info("查询菜单列表成功,父菜单ID={}, 菜单数量={}", parentId, menuList != null ? menuList.size() : 0);
+            return R.data(menuList, "查询成功");
+        } catch (Exception e) {
+            log.error("查询菜单列表失败,父菜单ID={}", parentId, e);
+            return R.fail("查询菜单列表失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 构建菜单树形结构
+     *
+     * @param flatList 扁平列表
+     * @return 树形结构列表
+     */
+    private List<LifeSysMenu> buildMenuTree(List<LifeSysMenu> flatList) {
+        if (flatList == null || flatList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 创建映射:ID到节点的映射,父ID到子节点列表的映射
+        Map<Long, LifeSysMenu> nodeMap = new HashMap<>();
+        Map<Long, List<LifeSysMenu>> parentChildMap = new HashMap<>();
+        List<LifeSysMenu> result = new ArrayList<>();
+
+        // 第一步:建立映射关系
+        for (LifeSysMenu menu : flatList) {
+            Long menuId = menu.getMenuId();
+            Long parentId = menu.getParentId() != null ? menu.getParentId() : 0L;
+
+            // 存入节点映射
+            nodeMap.put(menuId, menu);
+
+            // 如果是根节点(parentId为0或null),直接添加到结果
+            if (parentId == null || parentId == 0) {
+                result.add(menu);
+            } else {
+                // 否则,记录父子关系
+                parentChildMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(menu);
+            }
+        }
+
+        // 第二步:建立父子关系
+        for (LifeSysMenu menu : nodeMap.values()) {
+            Long menuId = menu.getMenuId();
+            if (parentChildMap.containsKey(menuId)) {
+                // 对子节点按排序值排序
+                List<LifeSysMenu> children = parentChildMap.get(menuId);
+                children.sort(Comparator.comparing(LifeSysMenu::getMenuSort, Comparator.nullsLast(Integer::compareTo)));
+                menu.setChildren(children);
+            }
+        }
+
+        // 对根节点按排序值排序
+        result.sort(Comparator.comparing(LifeSysMenu::getMenuSort, Comparator.nullsLast(Integer::compareTo)));
+
+        return result;
+    }
+}
+