|
|
|
|
@ -21,7 +21,8 @@ import java.util.*;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* 服务类
|
|
|
|
|
* 菜单权限服务实现类
|
|
|
|
|
* 处理菜单的增删改查、树形结构构建、导入导出等业务逻辑
|
|
|
|
|
* </p>
|
|
|
|
|
*
|
|
|
|
|
* @author qiujie
|
|
|
|
|
@ -31,16 +32,27 @@ import java.util.*;
|
|
|
|
|
public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private MenuMapper menuMapper;
|
|
|
|
|
private MenuMapper menuMapper; // 注入菜单数据访问层对象
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 新增菜单
|
|
|
|
|
* @param menu 菜单实体对象
|
|
|
|
|
* @return 统一响应结果(成功/失败)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO add(Menu menu) {
|
|
|
|
|
// 调用MyBatis-Plus的save方法保存菜单,成功返回成功响应,否则返回失败响应
|
|
|
|
|
if (save(menu)) {
|
|
|
|
|
return Response.success();
|
|
|
|
|
}
|
|
|
|
|
return Response.error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据ID删除菜单(逻辑删除,依赖MyBatis-Plus的逻辑删除配置)
|
|
|
|
|
* @param id 菜单ID
|
|
|
|
|
* @return 统一响应结果
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO delete(Integer id) {
|
|
|
|
|
if (removeById(id)) {
|
|
|
|
|
return Response.success();
|
|
|
|
|
@ -48,7 +60,12 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
return Response.error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
/**
|
|
|
|
|
* 批量删除菜单(逻辑删除)
|
|
|
|
|
* @param ids 菜单ID列表
|
|
|
|
|
* @return 统一响应结果
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class) // 声明事务,发生异常时回滚
|
|
|
|
|
public ResponseDTO deleteBatch(List<Integer> ids) {
|
|
|
|
|
if (removeBatchByIds(ids)) {
|
|
|
|
|
return Response.success();
|
|
|
|
|
@ -57,6 +74,11 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 编辑更新菜单信息
|
|
|
|
|
* @param menu 包含更新信息的菜单实体
|
|
|
|
|
* @return 统一响应结果
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO edit(Menu menu) {
|
|
|
|
|
if (updateById(menu)) {
|
|
|
|
|
return Response.success();
|
|
|
|
|
@ -65,6 +87,11 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据ID查询菜单详情
|
|
|
|
|
* @param id 菜单ID
|
|
|
|
|
* @return 统一响应结果(包含菜单详情)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO query(Integer id) {
|
|
|
|
|
Menu menu = getById(id);
|
|
|
|
|
if (menu != null) {
|
|
|
|
|
@ -74,23 +101,26 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查找所有菜单
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* 查找所有启用状态的菜单,并构建树形结构(一级菜单包含二级菜单,二级菜单包含权限点)
|
|
|
|
|
* @return 统一响应结果(包含树形结构的菜单列表)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO queryAll() {
|
|
|
|
|
// 查询所有状态为"正常"(1)的菜单
|
|
|
|
|
List<Menu> list = list(new QueryWrapper<Menu>().eq("status",1));
|
|
|
|
|
// 为父级菜单设置子菜单
|
|
|
|
|
// 一级菜单
|
|
|
|
|
|
|
|
|
|
// 筛选一级菜单(level=0)
|
|
|
|
|
List<Menu> firstList = list.stream().parallel()
|
|
|
|
|
.filter(menu -> menu.getLevel() == 0).toList();
|
|
|
|
|
|
|
|
|
|
// 为一级菜单设置二级菜单
|
|
|
|
|
for (Menu firstMenu : firstList) {
|
|
|
|
|
// 二级菜单
|
|
|
|
|
// 筛选当前一级菜单的二级菜单(parentId=一级菜单ID,level=1)
|
|
|
|
|
List<Menu> secondList = list.stream().parallel()
|
|
|
|
|
.filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList();
|
|
|
|
|
firstMenu.setChildren(secondList);
|
|
|
|
|
|
|
|
|
|
// 为二级菜单设置权限点(level=2)
|
|
|
|
|
for (Menu secondMenu : secondList) {
|
|
|
|
|
// 权限点
|
|
|
|
|
List<Menu> thirdList = list.stream().parallel()
|
|
|
|
|
.filter(menu -> Objects.equals(menu.getParentId(), secondMenu.getId())).toList();
|
|
|
|
|
secondMenu.setChildren(thirdList);
|
|
|
|
|
@ -100,28 +130,45 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分页条件查询菜单(仅查询一级菜单,同时关联查询其子菜单)
|
|
|
|
|
* @param current 当前页码
|
|
|
|
|
* @param size 每页条数
|
|
|
|
|
* @param name 菜单名称(模糊查询条件)
|
|
|
|
|
* @return 统一响应结果(包含分页信息和树形菜单列表)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO list(Integer current, Integer size, String name) {
|
|
|
|
|
// 构建分页对象
|
|
|
|
|
IPage<Menu> config = new Page<>(current, size);
|
|
|
|
|
QueryWrapper<Menu> wrapper = new QueryWrapper<>();
|
|
|
|
|
|
|
|
|
|
// 若名称不为空,添加模糊查询条件
|
|
|
|
|
if (name != "" && name != null) {
|
|
|
|
|
wrapper.like("name", name);
|
|
|
|
|
}
|
|
|
|
|
// 仅查询一级菜单(level=0)
|
|
|
|
|
wrapper.eq("level", 0);
|
|
|
|
|
|
|
|
|
|
// 执行分页查询
|
|
|
|
|
IPage<Menu> page = page(config, wrapper);
|
|
|
|
|
// 查询所有非一级菜单(用于构建子菜单)
|
|
|
|
|
List<Menu> list = list(new QueryWrapper<Menu>().ne("level", 0));
|
|
|
|
|
// 菜单
|
|
|
|
|
|
|
|
|
|
// 为一级菜单设置子菜单
|
|
|
|
|
List<Menu> firstList = page.getRecords();
|
|
|
|
|
for (Menu firstMenu : firstList) {
|
|
|
|
|
// 设置子菜单
|
|
|
|
|
// 筛选二级菜单
|
|
|
|
|
List<Menu> secondList = list.stream().filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList();
|
|
|
|
|
firstMenu.setChildren(secondList);
|
|
|
|
|
|
|
|
|
|
// 为二级菜单设置权限点
|
|
|
|
|
for (Menu secondMenu : secondList) {
|
|
|
|
|
// 设置子菜单
|
|
|
|
|
List<Menu> thirdList = list.stream().filter(menu -> Objects.equals(menu.getParentId(), secondMenu.getId())).toList();
|
|
|
|
|
secondMenu.setChildren(thirdList);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 将响应数据填充到map中
|
|
|
|
|
|
|
|
|
|
// 封装分页结果(总页数、总条数、菜单列表)
|
|
|
|
|
Map map = new HashMap();
|
|
|
|
|
map.put("pages", page.getPages());
|
|
|
|
|
map.put("total", page.getTotal());
|
|
|
|
|
@ -130,40 +177,50 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 数据导出
|
|
|
|
|
*
|
|
|
|
|
* @param response
|
|
|
|
|
* @return
|
|
|
|
|
* 导出菜单数据到Excel文件
|
|
|
|
|
* @param response HTTP响应对象(用于输出文件流)
|
|
|
|
|
* @param filename 导出文件名
|
|
|
|
|
* @throws IOException IO异常(如文件写入失败)
|
|
|
|
|
*/
|
|
|
|
|
public void export(HttpServletResponse response, String filename) throws IOException {
|
|
|
|
|
// 查询所有菜单
|
|
|
|
|
List<Menu> list = list();
|
|
|
|
|
// 调用工具类导出Excel
|
|
|
|
|
HutoolExcelUtil.writeExcel(response, list, filename, Menu.class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 数据导入
|
|
|
|
|
*
|
|
|
|
|
* @param file
|
|
|
|
|
* @return
|
|
|
|
|
* 从Excel文件导入菜单数据
|
|
|
|
|
* @param file 上传的Excel文件
|
|
|
|
|
* @return 统一响应结果
|
|
|
|
|
* @throws IOException IO异常(如文件读取失败)
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
@Transactional(rollbackFor = Exception.class) // 声明事务,确保批量插入的原子性
|
|
|
|
|
public ResponseDTO imp(MultipartFile file) throws IOException {
|
|
|
|
|
InputStream inputStream = file.getInputStream();
|
|
|
|
|
// 调用工具类读取Excel(从第2行开始读取,跳过表头)
|
|
|
|
|
List<Menu> list = HutoolExcelUtil.readExcel(inputStream, 1, Menu.class);
|
|
|
|
|
// IService接口中的方法.批量插入数据
|
|
|
|
|
// 批量插入数据
|
|
|
|
|
if (saveBatch(list)) {
|
|
|
|
|
return Response.success();
|
|
|
|
|
}
|
|
|
|
|
return Response.error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据员工ID查询其拥有的菜单权限(构建树形结构)
|
|
|
|
|
* @param id 员工ID
|
|
|
|
|
* @return 统一响应结果(包含员工可访问的树形菜单)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO queryByStaffId(Integer id) {
|
|
|
|
|
// 通过mapper查询该员工拥有的所有菜单
|
|
|
|
|
List<Menu> list = this.menuMapper.queryByStaffId(id);
|
|
|
|
|
// 一级菜单
|
|
|
|
|
|
|
|
|
|
// 筛选一级菜单并构建树形结构
|
|
|
|
|
List<Menu> firstList = list.stream().parallel()
|
|
|
|
|
.filter(menu -> menu.getLevel() == 0).toList();
|
|
|
|
|
for (Menu firstMenu : firstList) {
|
|
|
|
|
// 二级菜单
|
|
|
|
|
// 为一级菜单设置二级菜单
|
|
|
|
|
List<Menu> secondList = list.stream().parallel()
|
|
|
|
|
.filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList();
|
|
|
|
|
firstMenu.setChildren(secondList);
|
|
|
|
|
@ -172,11 +229,12 @@ public class MenuService extends ServiceImpl<MenuMapper, Menu> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据员工ID查询其拥有的权限标识集合(如"user:add"、"role:delete")
|
|
|
|
|
* @param id 员工ID
|
|
|
|
|
* @return 统一响应结果(包含权限标识列表)
|
|
|
|
|
*/
|
|
|
|
|
public ResponseDTO queryPermission(Integer id){
|
|
|
|
|
return Response.success(this.menuMapper.queryPermission(id));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|