feat(backend-java): 后台菜单接口改为返回菜单树并适配 admin-vue

菜单接口 /api/admin/current-user/menus 由扁平 route 列表改为含父子
层级的菜单树;权限标识用 column_key,页面地址用 route 单独下发;
/admin 与 / 入口重定向到 admin-vue。
This commit is contained in:
2026-09-05 14:58:02 +08:00
parent 1063e5188c
commit 2f71b4be3c
@@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -35,13 +37,13 @@ public class AdminConsoleController {
@GetMapping("/")
@Operation(summary = "根路径跳管理后台", hidden = true)
public String root() {
return "redirect:/admin.html";
return "redirect:/admin-vue/";
}
@GetMapping("/admin")
@Operation(summary = "管理后台入口", hidden = true)
public String adminPage() {
return "redirect:/admin.html";
return "redirect:/admin-vue/";
}
@GetMapping("/login")
@@ -68,21 +70,84 @@ public class AdminConsoleController {
}
@GetMapping("/api/admin/current-user/menus")
@Operation(summary = "当前登录管理员的可见菜单(扁平 route_path/name 列表)")
@Operation(summary = "当前登录管理员的可见后台菜单树")
public ApiResponse<Map<String, Object>> currentUserMenus(HttpServletRequest request) {
AdminUserEntity operator = adminAuthSupport.requireAdminOrInternal(request);
List<PermissionMenuItemVo> menus = permissionMenuService.getUserColumnPermissions(
operator, operator.getId(), PermissionMenuService.MENU_TYPE_ADMIN);
List<Map<String, String>> items = new ArrayList<>(menus.size());
return ApiResponse.success(Map.of("items", buildAdminMenuTree(menus)));
}
/**
* 将 columns 的有效权限项转换为新版后台菜单树。权限 key 使用 column_key
* 页面地址单独使用 route;这样后续调整 Vue URL 时不会改变授权标识。
*/
private List<Map<String, Object>> buildAdminMenuTree(List<PermissionMenuItemVo> menus) {
Map<Long, Map<String, Object>> nodes = new HashMap<>();
for (PermissionMenuItemVo menu : menus) {
if (menu.getRoutePath() == null || menu.getRoutePath().isBlank()) {
if (menu.getId() == null) {
continue;
}
Map<String, String> item = new LinkedHashMap<>();
item.put("route_path", menu.getRoutePath());
item.put("name", menu.getName() == null ? menu.getRoutePath() : menu.getName());
items.add(item);
Map<String, Object> node = new LinkedHashMap<>();
node.put("key", menu.getColumnKey() == null ? String.valueOf(menu.getId()) : menu.getColumnKey());
node.put("name", menu.getName() == null ? "未命名菜单" : menu.getName());
node.put("sort", menu.getSortOrder() == null ? 0 : menu.getSortOrder());
String route = adminRoute(menu.getColumnKey(), menu.getRoutePath());
if (route != null && !route.isBlank() && !route.startsWith("group-")) {
node.put("route", "/" + route.replaceFirst("^/", ""));
}
node.put("children", new ArrayList<Map<String, Object>>());
nodes.put(menu.getId(), node);
}
return ApiResponse.success(Map.of("items", items));
List<Map<String, Object>> roots = new ArrayList<>();
for (PermissionMenuItemVo menu : menus) {
Map<String, Object> node = nodes.get(menu.getId());
if (node == null) continue;
@SuppressWarnings("unchecked")
List<Map<String, Object>> children = (List<Map<String, Object>>) node.get("children");
if (menu.getParentId() != null && nodes.containsKey(menu.getParentId())) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> parentChildren = (List<Map<String, Object>>) nodes.get(menu.getParentId()).get("children");
parentChildren.add(node);
} else {
roots.add(node);
}
}
Comparator<Map<String, Object>> order = Comparator
.comparingInt((Map<String, Object> node) -> ((Number) node.get("sort")).intValue())
.thenComparing(node -> String.valueOf(node.get("key")));
sortMenuTree(roots, order);
stripSort(roots);
return roots;
}
private void sortMenuTree(List<Map<String, Object>> nodes,
Comparator<Map<String, Object>> order) {
nodes.sort(order);
for (Map<String, Object> node : nodes) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> children = (List<Map<String, Object>>) node.get("children");
sortMenuTree(children, order);
}
}
private void stripSort(List<Map<String, Object>> nodes) {
for (Map<String, Object> node : nodes) {
node.remove("sort");
@SuppressWarnings("unchecked")
List<Map<String, Object>> children = (List<Map<String, Object>>) node.get("children");
if (children.isEmpty()) node.remove("children");
else stripSort(children);
}
}
private String adminRoute(String columnKey, String storedRoute) {
if (columnKey == null) return storedRoute;
return switch (columnKey) {
case "admin_users" -> "account/users";
case "admin_columns" -> "account/menus";
case "admin_group_manage" -> "account/groups";
default -> storedRoute;
};
}
}