Files
KnowledgeBase/app/Filament/Resources/RoleResource.php
lizhuoran a17fe167b0 feat(权限): 创建角色管理资源(RoleResource)
- 创建 RoleResource 及其所有页面类
- 实现角色列表、创建、编辑、查看功能
- 权限选择器按模块分组显示,支持批量选择
- 实现 super-admin 角色保护(不可编辑和删除)
- 实现角色删除前检查(有关联用户时不可删除)
- 创建 RolePolicy 控制角色管理权限
- 在 AppServiceProvider 中注册 RolePolicy
- 角色列表显示权限数量和用户数量
- 完整的中文界面和提示信息
2026-03-11 10:00:29 +08:00

265 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\RoleResource\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class RoleResource extends Resource
{
protected static ?string $model = Role::class;
protected static ?string $navigationIcon = 'heroicon-o-shield-check';
protected static ?string $navigationLabel = '角色管理';
protected static ?string $modelLabel = '角色';
protected static ?string $pluralModelLabel = '角色';
protected static ?int $navigationSort = 5;
protected static ?string $navigationGroup = '系统管理';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('基本信息')
->schema([
Forms\Components\TextInput::make('name')
->label('角色标识')
->required()
->unique(ignoreRecord: true)
->maxLength(255)
->placeholder('例如: content-manager')
->helperText('角色的唯一标识符,使用小写字母和连字符')
->regex('/^[a-z0-9\-]+$/')
->validationMessages([
'regex' => '角色标识只能包含小写字母、数字和连字符',
])
->disabled(fn (?Role $record): bool => $record?->name === 'super-admin'),
Forms\Components\Select::make('guard_name')
->label('守卫')
->options([
'web' => 'Web',
])
->default('web')
->required()
->disabled(),
])
->columns(2),
Forms\Components\Section::make('权限配置')
->schema([
Forms\Components\CheckboxList::make('permissions')
->label('权限')
->relationship('permissions', 'name')
->options(function () {
return Permission::all()
->groupBy(function ($permission) {
// 按模块分组(取权限名称的第一部分)
return explode('.', $permission->name)[0];
})
->map(function ($permissions, $module) {
// 模块名称映射
$moduleNames = [
'document' => '文档管理',
'system-setting' => '系统设置',
'activity-log' => '操作日志',
'terminal' => '终端管理',
'sop-template' => 'SOP模板',
'group' => '分组管理',
'user' => '用户管理',
'role' => '角色管理',
];
$moduleName = $moduleNames[$module] ?? $module;
return $permissions->pluck('name', 'name')
->mapWithKeys(function ($name) use ($moduleName) {
// 操作名称映射
$action = explode('.', $name)[1] ?? '';
$actionNames = [
'viewAny' => '查看列表',
'view' => '查看详情',
'create' => '创建',
'update' => '编辑',
'delete' => '删除',
'download' => '下载',
'export' => '导出',
'sync' => '同步',
'publish' => '发布',
'archive' => '归档',
];
$actionName = $actionNames[$action] ?? $action;
$label = "{$moduleName} - {$actionName}";
return [$name => $label];
});
})
->flatten()
->toArray();
})
->columns(3)
->searchable()
->bulkToggleable()
->helperText('选择该角色拥有的权限')
->disabled(fn (?Role $record): bool => $record?->name === 'super-admin'),
])
->description('配置角色的权限super-admin 角色拥有所有权限且不可修改'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('角色标识')
->searchable()
->sortable()
->weight('bold')
->badge()
->color(fn (string $state): string => match ($state) {
'super-admin' => 'danger',
'admin' => 'warning',
'user' => 'success',
default => 'gray',
}),
Tables\Columns\TextColumn::make('guard_name')
->label('守卫')
->badge()
->sortable()
->toggleable(),
Tables\Columns\TextColumn::make('permissions_count')
->label('权限数量')
->counts('permissions')
->sortable()
->alignCenter()
->badge()
->color('info'),
Tables\Columns\TextColumn::make('users_count')
->label('用户数量')
->counts('users')
->sortable()
->alignCenter()
->badge()
->color('success'),
Tables\Columns\IconColumn::make('is_system')
->label('系统角色')
->boolean()
->trueIcon('heroicon-o-lock-closed')
->falseIcon('heroicon-o-lock-open')
->trueColor('danger')
->falseColor('gray')
->getStateUsing(fn (Role $record): bool => $record->name === 'super-admin')
->alignCenter()
->tooltip(fn (Role $record): string =>
$record->name === 'super-admin'
? '系统角色,不可删除'
: '可以删除'
),
Tables\Columns\TextColumn::make('created_at')
->label('创建时间')
->dateTime('Y-m-d H:i:s')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('更新时间')
->dateTime('Y-m-d H:i:s')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\SelectFilter::make('guard_name')
->label('守卫')
->options([
'web' => 'Web',
]),
])
->actions([
Tables\Actions\ViewAction::make()
->label('查看'),
Tables\Actions\EditAction::make()
->label('编辑')
->visible(fn (Role $record): bool => $record->name !== 'super-admin'),
Tables\Actions\DeleteAction::make()
->label('删除')
->visible(fn (Role $record): bool => $record->name !== 'super-admin')
->before(function (Tables\Actions\DeleteAction $action, Role $record) {
// 检查是否有关联用户
if ($record->users()->count() > 0) {
\Filament\Notifications\Notification::make()
->danger()
->title('无法删除')
->body("该角色还有 {$record->users()->count()} 个用户,请先移除用户的角色后再删除。")
->persistent()
->send();
$action->cancel();
}
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()
->label('批量删除')
->before(function (Tables\Actions\DeleteBulkAction $action, $records) {
// 检查是否包含 super-admin
if ($records->contains('name', 'super-admin')) {
\Filament\Notifications\Notification::make()
->danger()
->title('无法删除')
->body('不能删除 super-admin 角色')
->persistent()
->send();
$action->cancel();
return;
}
// 检查是否有关联用户
$rolesWithUsers = $records->filter(fn ($role) => $role->users()->count() > 0);
if ($rolesWithUsers->count() > 0) {
$roleNames = $rolesWithUsers->pluck('name')->join('、');
\Filament\Notifications\Notification::make()
->danger()
->title('无法删除')
->body("以下角色还有关联用户:{$roleNames},请先移除用户的角色后再删除。")
->persistent()
->send();
$action->cancel();
}
}),
]),
])
->defaultSort('created_at', 'desc');
}
public static function getPages(): array
{
return [
'index' => Pages\ListRoles::route('/'),
'create' => Pages\CreateRole::route('/create'),
'edit' => Pages\EditRole::route('/{record}/edit'),
'view' => Pages\ViewRole::route('/{record}'),
];
}
}