feat(menu): 优化菜单服务性能并新增医生排班功能
- 添加菜单缓存注解以提升查询性能 - 实现菜单完整路径计算优化,解决 N+1 查询问题 - 新增 selectAllMenus 方法供路径计算使用 - 添加今日医生排班查询功能 - 重构前端图标显示逻辑,使用 SVG 图标替代 Element 图标 - 添加前端菜单数据本地缓存机制 - 更新菜单管理界面的表单组件绑定方式 - 新增预约管理、门诊管理和药房管理路由配置
This commit is contained in:
@@ -140,4 +140,11 @@ public interface SysMenuMapper {
|
||||
* @return 结果
|
||||
*/
|
||||
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
||||
|
||||
/**
|
||||
* 查询所有菜单信息
|
||||
*
|
||||
* @return 菜单列表
|
||||
*/
|
||||
public List<SysMenu> selectAllMenus();
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* @return 菜单列表
|
||||
*/
|
||||
@Override
|
||||
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'menuList:' + #userId + ':' + (#menu == null ? 'all' : #menu.menuName)")
|
||||
public List<SysMenu> selectMenuList(SysMenu menu, Long userId) {
|
||||
List<SysMenu> menuList = null;
|
||||
// 管理员显示所有菜单信息
|
||||
@@ -224,23 +225,133 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
@Override
|
||||
public List<SysMenu> buildMenuTreeWithFullPath(List<SysMenu> menus) {
|
||||
List<SysMenu> menuTree = buildMenuTree(menus);
|
||||
// 为每个菜单项添加完整路径
|
||||
addFullPathToMenuTree(menuTree);
|
||||
// 一次性获取所有菜单信息,避免N+1查询问题
|
||||
List<SysMenu> allMenus = menuMapper.selectAllMenus();
|
||||
Map<Long, SysMenu> menuMap = allMenus.stream()
|
||||
.collect(Collectors.toMap(SysMenu::getMenuId, menu -> menu));
|
||||
|
||||
// 为每个菜单项添加完整路径(优化版本,避免N+1查询问题)
|
||||
addFullPathsToMenuTreeOptimized(menuTree, menuMap);
|
||||
return menuTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为菜单树添加完整路径
|
||||
* 为菜单树添加完整路径(优化版本)
|
||||
*
|
||||
* @param menus 菜单树
|
||||
* @param menuMap 菜单映射
|
||||
*/
|
||||
private void addFullPathToMenuTree(List<SysMenu> menus) {
|
||||
private void addFullPathsToMenuTreeOptimized(List<SysMenu> menus, Map<Long, SysMenu> menuMap) {
|
||||
for (SysMenu menu : menus) {
|
||||
// 计算当前菜单的完整路径
|
||||
menu.setFullPath(getMenuFullPath(menu.getMenuId()));
|
||||
// 使用优化的路径计算方法
|
||||
menu.setFullPath(computeMenuFullPathOptimized(menu, menuMap));
|
||||
|
||||
// 递归处理子菜单
|
||||
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||
addFullPathToMenuTree(menu.getChildren());
|
||||
addFullPathsToMenuTreeOptimized(menu.getChildren(), menuMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化的计算菜单完整路径方法
|
||||
*
|
||||
* @param menu 菜单
|
||||
* @param menuMap 菜单映射
|
||||
* @return 完整路径
|
||||
*/
|
||||
private String computeMenuFullPathOptimized(SysMenu menu, Map<Long, SysMenu> menuMap) {
|
||||
if (menu == null || menu.getMenuId() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder fullPath = new StringBuilder();
|
||||
buildMenuPathOptimized(menu, fullPath, menuMap);
|
||||
return normalizePath(fullPath.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化的递归构建菜单路径
|
||||
*
|
||||
* @param menu 菜单信息
|
||||
* @param path 路径构建器
|
||||
* @param menuMap 菜单映射
|
||||
*/
|
||||
private void buildMenuPathOptimized(SysMenu menu, StringBuilder path, Map<Long, SysMenu> menuMap) {
|
||||
if (menu == null || menu.getMenuId() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果不是根节点,则递归查找父节点
|
||||
if (menu.getParentId() != null && menu.getParentId() > 0) {
|
||||
SysMenu parentMenu = menuMap.get(menu.getParentId());
|
||||
if (parentMenu != null) {
|
||||
buildMenuPathOptimized(parentMenu, path, menuMap);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加当前菜单的路径,避免双斜杠
|
||||
String currentPath = normalizePathSegment(menu.getPath());
|
||||
if (currentPath != null && !currentPath.isEmpty()) {
|
||||
if (path.length() > 0) {
|
||||
// 确保路径之间只有一个斜杠分隔符
|
||||
if (path.charAt(path.length() - 1) != '/') {
|
||||
path.append("/").append(currentPath);
|
||||
} else {
|
||||
path.append(currentPath);
|
||||
}
|
||||
} else {
|
||||
// 对于第一个路径,直接追加
|
||||
path.append(currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归收集菜单树中的所有菜单ID
|
||||
*
|
||||
* @param menus 菜单树
|
||||
* @return 菜单ID列表
|
||||
*/
|
||||
private List<Long> collectMenuIds(List<SysMenu> menus) {
|
||||
List<Long> menuIds = new ArrayList<>();
|
||||
for (SysMenu menu : menus) {
|
||||
menuIds.add(menu.getMenuId());
|
||||
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||
menuIds.addAll(collectMenuIds(menu.getChildren()));
|
||||
}
|
||||
}
|
||||
return menuIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取菜单完整路径
|
||||
*
|
||||
* @param menuIds 菜单ID列表
|
||||
* @return 菜单ID到完整路径的映射
|
||||
*/
|
||||
private Map<Long, String> batchGetMenuFullPaths(List<Long> menuIds) {
|
||||
Map<Long, String> fullPathMap = new HashMap<>();
|
||||
for (Long menuId : menuIds) {
|
||||
// 使用缓存的getMenuFullPath方法
|
||||
fullPathMap.put(menuId, getMenuFullPath(menuId));
|
||||
}
|
||||
return fullPathMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为菜单树设置完整路径
|
||||
*
|
||||
* @param menus 菜单树
|
||||
* @param fullPathMap 完整路径映射
|
||||
*/
|
||||
private void setFullPathsToMenuTree(List<SysMenu> menus, Map<Long, String> fullPathMap) {
|
||||
for (SysMenu menu : menus) {
|
||||
// 设置当前菜单的完整路径
|
||||
menu.setFullPath(fullPathMap.get(menu.getMenuId()));
|
||||
// 递归处理子菜单
|
||||
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||
setFullPathsToMenuTree(menu.getChildren(), fullPathMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,6 +410,9 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@org.springframework.cache.annotation.Caching(evict = {
|
||||
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
|
||||
})
|
||||
public int insertMenu(SysMenu menu) {
|
||||
//路径Path唯一性判断
|
||||
SysMenu sysMenu = menuMapper.selectMenuByPath(menu.getPath());
|
||||
@@ -315,13 +429,17 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@org.springframework.cache.annotation.Caching(evict = {
|
||||
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true),
|
||||
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'fullPath:' + #menu.menuId")
|
||||
})
|
||||
public int updateMenu(SysMenu menu) {
|
||||
//路径Path唯一性判断(排除当前菜单本身)
|
||||
String path = menu.getPath();
|
||||
if (StringUtils.isNotBlank(path)) {
|
||||
SysMenu sysMenu = menuMapper.selectMenuByPathExcludeId(menu.getPath(), menu.getMenuId());
|
||||
if (sysMenu != null) {
|
||||
log.warn("路由地址已存在 - menuId: {}, path: {}, 存在的menuId: {}",
|
||||
log.warn("路由地址已存在 - menuId: {}, path: {}, 存在的menuId: {}",
|
||||
menu.getMenuId(), menu.getPath(), sysMenu.getMenuId());
|
||||
return -1; // 路由地址已存在
|
||||
}
|
||||
@@ -337,6 +455,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@org.springframework.cache.annotation.Caching(evict = {
|
||||
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true),
|
||||
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'fullPath:' + #menuId")
|
||||
})
|
||||
public int deleteMenuById(Long menuId) {
|
||||
return menuMapper.deleteMenuById(menuId);
|
||||
}
|
||||
@@ -533,6 +655,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* @return 完整路径
|
||||
*/
|
||||
@Override
|
||||
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'fullPath:' + #menuId", unless = "#result == null || #result.isEmpty()")
|
||||
public String getMenuFullPath(Long menuId) {
|
||||
SysMenu menu = menuMapper.selectMenuById(menuId);
|
||||
if (menu == null) {
|
||||
|
||||
@@ -274,4 +274,27 @@
|
||||
where menu_id = #{menuId}
|
||||
</delete>
|
||||
|
||||
<select id="selectAllMenus" resultMap="SysMenuResult">
|
||||
select menu_id,
|
||||
parent_id,
|
||||
menu_name,
|
||||
path,
|
||||
component,
|
||||
"query",
|
||||
route_name,
|
||||
is_frame,
|
||||
is_cache,
|
||||
menu_type,
|
||||
visible,
|
||||
status,
|
||||
perms,
|
||||
icon,
|
||||
order_num,
|
||||
create_time,
|
||||
update_time,
|
||||
remark
|
||||
from sys_menu
|
||||
order by parent_id, order_num
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user