feat(menu): 添加菜单缓存刷新功能和拖拽排序支持

- 在SysMenuController中添加refreshCache和refreshCurrentUserMenuCache接口
- 实现菜单缓存的按需刷新和用户级别缓存清理功能
- 优化菜单列表查询的缓存key策略,支持更精确的缓存命中
- 为菜单树查询添加缓存注解提升性能
- 在菜单增删改操作中完善缓存清理逻辑
- 添加allocateMenuToRole方法实现菜单角色分配功能
- 在前端DictTag组件中修复标签类型验证逻辑
- 为首页配置页面添加拖拽排序功能,支持快捷功能重新排列
- 集成Sortable.js实现拖拽交互和排序保存
- 优化菜单管理页面的缓存刷新机制和数据展示
- 完善配置更新事件处理,支持实时配置同步
This commit is contained in:
2026-02-05 23:07:31 +08:00
parent cd6c015d8f
commit f3d56bff45
8 changed files with 356 additions and 24 deletions

View File

@@ -138,4 +138,26 @@ public class SysMenuController extends BaseController {
String fullPath = menuService.generateFullPath(parentId, currentPath);
return success(fullPath);
}
/**
* 刷新菜单缓存
*/
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@Log(title = "菜单管理", businessType = BusinessType.OTHER)
@PostMapping("/refreshCache")
public AjaxResult refreshCache() {
menuService.refreshMenuCache();
return success("菜单缓存已刷新");
}
/**
* 强制刷新当前用户菜单缓存
*/
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@Log(title = "菜单管理", businessType = BusinessType.OTHER)
@PostMapping("/refreshCurrentUserMenuCache")
public AjaxResult refreshCurrentUserMenuCache() {
menuService.clearMenuCacheByUserId(getUserId());
return success("当前用户菜单缓存已刷新");
}
}

View File

@@ -165,4 +165,23 @@ public interface ISysMenuService {
* @return 完整路径
*/
public String generateFullPath(Long parentId, String currentPath);
/**
* 刷新菜单缓存
*/
public void refreshMenuCache();
/**
* 根据用户ID清除菜单缓存
*/
public void clearMenuCacheByUserId(Long userId);
/**
* 将菜单分配给角色
*
* @param roleId 角色ID
* @param menuIds 菜单ID列表
* @return 结果
*/
public int allocateMenuToRole(Long roleId, List<Long> menuIds);
}

View File

@@ -8,6 +8,7 @@ import com.core.common.core.domain.entity.SysRole;
import com.core.common.core.domain.entity.SysUser;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.StringUtils;
import com.core.system.domain.SysRoleMenu;
import com.core.system.domain.vo.MetaVo;
import com.core.system.domain.vo.RouterVo;
import com.core.system.mapper.SysMenuMapper;
@@ -54,12 +55,12 @@ public class SysMenuServiceImpl implements ISysMenuService {
/**
* 查询系统菜单列表
*
*
* @param menu 菜单信息
* @return 菜单列表
*/
@Override
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'menuList:' + #userId + ':' + (#menu == null ? 'all' : #menu.menuName)")
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'menuList:' + #userId + ':' + (#menu == null ? 'all' : (#menu.menuName != null ? #menu.menuName : 'all') + ':' + (#menu.visible != null ? #menu.visible : 'all') + ':' + (#menu.status != null ? #menu.status : 'all'))")
public List<SysMenu> selectMenuList(SysMenu menu, Long userId) {
List<SysMenu> menuList = null;
// 管理员显示所有菜单信息
@@ -110,11 +111,12 @@ public class SysMenuServiceImpl implements ISysMenuService {
/**
* 根据用户ID查询菜单
*
*
* @param userId 用户名称
* @return 菜单列表
*/
@Override
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'menuTree:' + #userId")
public List<SysMenu> selectMenuTreeByUserId(Long userId) {
List<SysMenu> menus = null;
if (SecurityUtils.isAdmin(userId)) {
@@ -405,11 +407,12 @@ public class SysMenuServiceImpl implements ISysMenuService {
/**
* 新增保存菜单信息
*
*
* @param menu 菜单信息
* @return 结果
*/
@Override
@org.springframework.transaction.annotation.Transactional
@org.springframework.cache.annotation.Caching(evict = {
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
})
@@ -419,19 +422,27 @@ public class SysMenuServiceImpl implements ISysMenuService {
if (sysMenu != null){
return -1;
}
return menuMapper.insertMenu(menu);
int rows = menuMapper.insertMenu(menu);
// 如果是管理员创建菜单,自动分配给所有角色(可选逻辑)
// 或者,可以将新菜单分配给创建者所属的角色
// 这里我们暂时不自动分配,因为这可能不符合安全最佳实践
return rows;
}
/**
* 修改保存菜单信息
*
*
* @param menu 菜单信息
* @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")
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'fullPath:' + #menu.menuId"),
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'menuTree:' + #menu.updateBy")
})
public int updateMenu(SysMenu menu) {
//路径Path唯一性判断排除当前菜单本身
@@ -450,14 +461,13 @@ public class SysMenuServiceImpl implements ISysMenuService {
/**
* 删除菜单管理信息
*
*
* @param menuId 菜单ID
* @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")
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
})
public int deleteMenuById(Long menuId) {
return menuMapper.deleteMenuById(menuId);
@@ -776,4 +786,50 @@ public class SysMenuServiceImpl implements ISysMenuService {
return normalizePath(fullPath.toString());
}
/**
* 刷新菜单缓存
*/
@Override
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
public void refreshMenuCache() {
log.info("菜单缓存已刷新");
}
/**
* 根据用户ID清除菜单缓存
*/
@Override
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'menuTree:' + #userId")
public void clearMenuCacheByUserId(Long userId) {
log.info("清除用户 {} 的菜单树缓存", userId);
}
/**
* 将菜单分配给角色
*
* @param roleId 角色ID
* @param menuIds 菜单ID列表
* @return 结果
*/
@Override
@org.springframework.transaction.annotation.Transactional
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
public int allocateMenuToRole(Long roleId, List<Long> menuIds) {
// 先删除该角色现有的所有菜单权限
roleMenuMapper.deleteRoleMenuByRoleId(roleId);
// 重新分配菜单给角色
if (menuIds != null && !menuIds.isEmpty()) {
List<SysRoleMenu> roleMenuList = new ArrayList<>();
for (Long menuId : menuIds) {
SysRoleMenu rm = new SysRoleMenu();
rm.setRoleId(roleId);
rm.setMenuId(menuId);
roleMenuList.add(rm);
}
return roleMenuMapper.batchRoleMenu(roleMenuList);
}
return 0;
}
}