where('is_visible', true) ->where(function ($query) { $query->whereNull('path')->orWhere('path', '!=', '/study-tours/categories'); }) ->orderBy('sort') ->orderBy('id'); $user = $request->user(); if ($user && Schema::hasTable('role_menu_permissions')) { $roleMenuIds = RoleMenuPermission::query() ->where('role', (string) $user->role) ->pluck('menu_id') ->map(fn ($id) => (int) $id) ->values(); if ($roleMenuIds->isNotEmpty()) { $query->whereIn('id', $roleMenuIds); } } $menus = $query->get(['id', 'name', 'path', 'icon', 'parent_id', 'sort']); $visibleIds = $menus->pluck('id')->map(fn ($id) => (int) $id)->values(); if ($visibleIds->isNotEmpty()) { $parentIds = $menus->pluck('parent_id')->map(fn ($id) => (int) $id)->filter(fn ($id) => $id > 0)->unique()->values(); if ($parentIds->isNotEmpty()) { $parents = AdminMenu::query() ->whereIn('id', $parentIds) ->where('is_visible', true) ->get(['id', 'name', 'path', 'icon', 'parent_id', 'sort']); $menus = $menus->merge($parents)->unique('id')->sortBy([['sort', 'asc'], ['id', 'asc']])->values(); } } return response()->json($this->buildTree($menus)); } public function listAll(Request $request): JsonResponse { $menus = AdminMenu::query() ->orderBy('sort') ->orderBy('id') ->get(['id', 'name', 'path', 'icon', 'parent_id', 'sort', 'is_visible']); return response()->json($menus); } public function store(Request $request): JsonResponse { $this->ensureSuperAdmin($request); $data = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'path' => ['nullable', 'string', 'max:255'], 'icon' => ['nullable', 'string', 'max:100'], 'parent_id' => ['nullable', 'integer', 'min:0'], 'sort' => ['nullable', 'integer', 'min:0'], 'is_visible' => ['nullable', 'boolean'], ]); $parentId = (int) ($data['parent_id'] ?? 0); if ($parentId > 0) { $exists = AdminMenu::query()->where('id', $parentId)->exists(); abort_unless($exists, 422, '父级菜单不存在'); } $menu = AdminMenu::create([ 'name' => $data['name'], 'path' => $data['path'] ?? null, 'icon' => $data['icon'] ?? null, 'parent_id' => $parentId, 'sort' => (int) ($data['sort'] ?? 0), 'is_visible' => (bool) ($data['is_visible'] ?? true), ]); return response()->json($menu, 201); } public function update(Request $request, AdminMenu $adminMenu): JsonResponse { $this->ensureSuperAdmin($request); $data = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'path' => ['nullable', 'string', 'max:255'], 'icon' => ['nullable', 'string', 'max:100'], 'parent_id' => ['nullable', 'integer', 'min:0'], 'sort' => ['nullable', 'integer', 'min:0'], 'is_visible' => ['nullable', 'boolean'], ]); $parentId = (int) ($data['parent_id'] ?? 0); if ($parentId > 0) { abort_unless($parentId !== $adminMenu->id, 422, '父级菜单不能是自身'); $exists = AdminMenu::query()->where('id', $parentId)->exists(); abort_unless($exists, 422, '父级菜单不存在'); } $adminMenu->fill([ 'name' => $data['name'], 'path' => $data['path'] ?? null, 'icon' => $data['icon'] ?? null, 'parent_id' => $parentId, 'sort' => (int) ($data['sort'] ?? 0), 'is_visible' => (bool) ($data['is_visible'] ?? true), ])->save(); return response()->json($adminMenu); } public function destroy(Request $request, AdminMenu $adminMenu): JsonResponse { $this->ensureSuperAdmin($request); $hasChildren = AdminMenu::query()->where('parent_id', $adminMenu->id)->exists(); abort_if($hasChildren, 422, '请先删除子菜单'); $adminMenu->delete(); return response()->json(['message' => '删除成功']); } private function normalizeMenuName(string $name): string { if ($name === '黑名单管理') { return '用户管理'; } return $name; } private function ensureSuperAdmin(Request $request): void { abort_unless($request->user()?->isSuperAdmin(), 403, '仅超级管理员可操作'); } private function buildTree($menus): array { return $menus->where('parent_id', 0)->values()->map(function (AdminMenu $menu) use ($menus) { $children = $menus ->where('parent_id', $menu->id) ->values() ->map(fn (AdminMenu $child) => [ 'id' => $child->id, 'name' => $this->normalizeMenuName($child->name), 'path' => $child->path, 'icon' => $child->icon, ]) ->all(); return [ 'id' => $menu->id, 'name' => $this->normalizeMenuName($menu->name), 'path' => $menu->path, 'icon' => $menu->icon, 'children' => $children, ]; })->all(); } }