diff --git a/app/Http/Controllers/Settings/Navigation.php b/app/Http/Controllers/Settings/Navigation.php index 28c1f269..2ded2fc8 100644 --- a/app/Http/Controllers/Settings/Navigation.php +++ b/app/Http/Controllers/Settings/Navigation.php @@ -13,7 +13,7 @@ class Navigation extends Controller parent::__construct(); $this->middleware(function ($request, $next) { - abort_unless(user()?->hasRole('admin'), 403); + abort_unless(\App\Utilities\SystemAccess::canOpenSettings(), 403); return $next($request); }); diff --git a/app/Http/Controllers/SystemSettings/Sidebar.php b/app/Http/Controllers/SystemSettings/Sidebar.php index 68328ebd..819180e6 100644 --- a/app/Http/Controllers/SystemSettings/Sidebar.php +++ b/app/Http/Controllers/SystemSettings/Sidebar.php @@ -21,6 +21,11 @@ class Sidebar extends Controller }); } + public function index() + { + return view('system_settings.sidebar.index'); + } + public function edit(Request $request) { $subjects = $this->subjects(); @@ -63,7 +68,7 @@ class Sidebar extends Controller flash('保存成功,侧边栏权限已更新。')->success(); - return redirect()->route('dashboard'); + return redirect()->route('system-settings.sidebar.edit', ['subject' => $subject]); } private function subjects(): array @@ -72,7 +77,6 @@ class Sidebar extends Controller if (SystemAccess::isSuperAdmin()) { $subjects = [ - 'role_super_admin' => '用户类型:' . $labels[SystemAccess::SUPER_ADMIN], 'role_admin' => '用户类型:' . $labels[SystemAccess::ADMIN], 'role_user' => '用户类型:' . $labels[SystemAccess::USER], ]; @@ -94,6 +98,9 @@ class Sidebar extends Controller foreach ($users as $managedUser) { $role = SystemAccess::roleName($managedUser); + if ($role === SystemAccess::SUPER_ADMIN) { + continue; + } $subjects['user_' . $managedUser->id] = '指定用户:' . $managedUser->name . ' - ' . ($labels[$role] ?? $role); } diff --git a/app/Http/Controllers/SystemSettings/Users.php b/app/Http/Controllers/SystemSettings/Users.php index e6a78333..d235de0c 100644 --- a/app/Http/Controllers/SystemSettings/Users.php +++ b/app/Http/Controllers/SystemSettings/Users.php @@ -87,12 +87,14 @@ class Users extends Controller $role = Role::where('name', $data['role'])->firstOrFail(); if ( - $managedUser->id === user()->id - && SystemAccess::isSuperAdmin($managedUser) - && $data['role'] !== SystemAccess::SUPER_ADMIN + SystemAccess::isSuperAdmin($managedUser) + && $managedUser->enabled + && ($data['role'] !== SystemAccess::SUPER_ADMIN || ! ($data['enabled'] ?? false)) && $this->superAdminCount() <= 1 ) { - return back()->withErrors(['role' => '系统至少需要保留一名超级管理员。'])->withInput(); + return back()->withErrors([ + $data['role'] !== SystemAccess::SUPER_ADMIN ? 'role' : 'enabled' => '系统至少需要保留一名启用的主管理员。', + ])->withInput(); } if ($managedUser->id === user()->id && ! ($data['enabled'] ?? false)) { @@ -111,9 +113,11 @@ class Users extends Controller } $managedUser->update($attributes); - $managedUser->roles()->sync([$role->id]); + $managedUser->syncRoles([$role->id]); }); + $managedUser->flushCache(); + flash('用户已修改。')->success(); return redirect()->route('system-settings.users.index'); @@ -126,8 +130,8 @@ class Users extends Controller abort_if($managedUser->id === user()->id, 422, '不能删除当前登录账号。'); abort_unless(SystemAccess::canManageUser(user(), $managedUser), 403); - if (SystemAccess::isSuperAdmin($managedUser) && $this->superAdminCount() <= 1) { - return back()->withErrors(['user' => '系统至少需要保留一名超级管理员。']); + if (SystemAccess::isSuperAdmin($managedUser) && $managedUser->enabled && $this->superAdminCount() <= 1) { + return back()->withErrors(['user' => '系统至少需要保留一名启用的主管理员。']); } $managedUser->delete(); @@ -143,10 +147,6 @@ class Users extends Controller $company->where('companies.id', company_id()); }); - if (! SystemAccess::isSuperAdmin()) { - $query->whereHas('roles', fn ($roles) => $roles->where('roles.name', SystemAccess::USER)); - } - return $query; } @@ -176,6 +176,7 @@ class Users extends Controller private function superAdminCount(): int { return User::query() + ->where('enabled', true) ->whereHas('roles', fn ($roles) => $roles->where('roles.name', SystemAccess::SUPER_ADMIN)) ->count(); } diff --git a/app/Http/Livewire/Menu/Settings.php b/app/Http/Livewire/Menu/Settings.php index 9d0cc611..6debfa40 100644 --- a/app/Http/Livewire/Menu/Settings.php +++ b/app/Http/Livewire/Menu/Settings.php @@ -26,7 +26,7 @@ class Settings extends Component $items = [ ['system-settings.users.index', '用户管理', 'people', '用户 类型 权限'], - ['system-settings.sidebar.edit', '侧边栏管理', 'menu', '侧边栏 用户类型 指定管理员'], + ['system-settings.permissions.index', '权限管理', 'admin_panel_settings', '侧边栏 用户页面 访问权限 管理员 身份'], ['system-settings.databases.index', '数据库管理', 'storage', '系统数据库 云数据库 上游 连接 测试'], ]; @@ -38,6 +38,8 @@ class Settings extends Component $item = $menu->route($route, $title, [], ($index + 1) * 10, [ 'icon' => $icon, 'search_keywords' => $keywords, + 'active' => fn () => request()->routeIs(Str::beforeLast($route, '.') . '.*') + || ($route === 'system-settings.permissions.index' && request()->routeIs('system-settings.sidebar.*')), ]); if ($item->isActive()) { diff --git a/app/Http/Requests/Auth/User.php b/app/Http/Requests/Auth/User.php index 88e7a5cb..c0f76b47 100644 --- a/app/Http/Requests/Auth/User.php +++ b/app/Http/Requests/Auth/User.php @@ -14,6 +14,30 @@ class User extends FormRequest */ public function authorize() { + $actor = $this->user(); + if ($actor && ! \App\Utilities\SystemAccess::isSuperAdmin($actor)) { + $target = $this->route('user'); + $target = $target instanceof \App\Models\Auth\User ? $target : \App\Models\Auth\User::find($target); + if ($target && $target->id !== $actor->id && \App\Utilities\SystemAccess::canOpenSettings($target)) { + return false; + } + if ($this->filled('permissions')) { + return false; + } + if ($this->has('roles')) { + $requested = array_map('strval', (array) $this->input('roles')); + $current = $target ? $target->roles()->pluck('id')->map(fn ($id) => (string) $id)->all() : []; + sort($requested); + sort($current); + if ($requested !== $current) { + $allowed = \App\Models\Auth\Role::where('name', 'user')->pluck('id')->map(fn ($id) => (string) $id)->all(); + if (array_diff($requested, $allowed)) { + return false; + } + } + } + } + return true; } diff --git a/app/Listeners/Menu/ShowInSettings.php b/app/Listeners/Menu/ShowInSettings.php index cef742aa..100e4660 100644 --- a/app/Listeners/Menu/ShowInSettings.php +++ b/app/Listeners/Menu/ShowInSettings.php @@ -19,7 +19,7 @@ class ShowInSettings { $menu = $event->menu; - if (user()?->hasRole('admin')) { + if (\App\Utilities\SystemAccess::canOpenSettings()) { $menu->route('settings.navigation.manage', '侧边栏功能名称', [], 75, [ 'icon' => 'menu', 'search_keywords' => '侧边栏 功能 名称', diff --git a/app/Utilities/SidebarPermissions.php b/app/Utilities/SidebarPermissions.php index 0c36a020..04e4575d 100644 --- a/app/Utilities/SidebarPermissions.php +++ b/app/Utilities/SidebarPermissions.php @@ -31,6 +31,10 @@ class SidebarPermissions public static function allowedKeys(User $user): ?array { + if (SystemAccess::isSuperAdmin($user)) { + return null; + } + $settings = self::settings(); $subject = self::subjectKey($user); @@ -57,7 +61,7 @@ class SidebarPermissions return $section; } - $pages = array_values(array_filter($section['pages'] ?? [], function (array $page) use ($allowed, $sectionKey) { + $pages = array_values(array_filter(array_map(function (array $page) use ($allowed, $sectionKey) { $pageKey = $sectionKey . '/' . $page['slug']; if (in_array($pageKey, $allowed, true)) { @@ -67,7 +71,7 @@ class SidebarPermissions return in_array($sectionKey . '/' . $child['slug'], $allowed, true); })); } - return true; + return $page; } // 子页面可能在 allowed 列表中(独立 URL),父级分组也允许展开 @@ -77,12 +81,12 @@ class SidebarPermissions })); if (! empty($visibleChildren)) { $page['children'] = $visibleChildren; - return true; + return $page; } } - return false; - })); + return null; + }, $section['pages'] ?? []))); if (! empty($pages)) { $section['pages'] = $pages; diff --git a/app/Utilities/SystemAccess.php b/app/Utilities/SystemAccess.php index 4632792b..0b39f376 100644 --- a/app/Utilities/SystemAccess.php +++ b/app/Utilities/SystemAccess.php @@ -18,8 +18,11 @@ class SystemAccess return ''; } + // 身份变更必须立即生效,不能沿用权限库中已缓存的旧角色。 + $roles = $user->roles()->pluck('name')->all(); + foreach ([self::SUPER_ADMIN, self::ADMIN, self::USER] as $role) { - if ($user->hasRole($role)) { + if (in_array($role, $roles, true)) { return $role; } } @@ -53,8 +56,8 @@ class SystemAccess if (self::isSuperAdmin($actor)) { return [ - self::SUPER_ADMIN => '超级管理员', - self::ADMIN => '普通管理员', + self::SUPER_ADMIN => '主管理员(最高权限)', + self::ADMIN => '管理员', self::USER => '普通用户', ]; } @@ -65,8 +68,8 @@ class SystemAccess public static function roleLabels(): array { return [ - self::SUPER_ADMIN => '超级管理员', - self::ADMIN => '普通管理员', + self::SUPER_ADMIN => '主管理员', + self::ADMIN => '管理员', self::USER => '普通用户', ]; } diff --git a/resources/views/system_settings/partials/navigation-script.blade.php b/resources/views/system_settings/partials/navigation-script.blade.php new file mode 100644 index 00000000..351c9cbf --- /dev/null +++ b/resources/views/system_settings/partials/navigation-script.blade.php @@ -0,0 +1,74 @@ +@once +@push('scripts_start') + +@endpush +@endonce diff --git a/resources/views/system_settings/partials/navigation.blade.php b/resources/views/system_settings/partials/navigation.blade.php index b43c8795..65e1e1d4 100644 --- a/resources/views/system_settings/partials/navigation.blade.php +++ b/resources/views/system_settings/partials/navigation.blade.php @@ -1,21 +1,23 @@ -