refactor: kb & station & terminal
This commit is contained in:
@@ -40,11 +40,11 @@ class DocumentResource extends Resource
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
|
||||
// 应用 accessibleBy 作用域,确保用户只能看到有权限的文档
|
||||
$user = auth()->user();
|
||||
if ($user) {
|
||||
$query->accessibleBy($user);
|
||||
|
||||
if ($user && $user->hasStationRestriction()) {
|
||||
$accessibleKbIds = \App\Models\KnowledgeBase::accessibleBy($user)->pluck('id');
|
||||
$query->whereIn('knowledge_base_id', $accessibleKbIds);
|
||||
}
|
||||
|
||||
return $query;
|
||||
@@ -86,29 +86,13 @@ class DocumentResource extends Resource
|
||||
->helperText('支持 .docx/.pptx/.xlsx/.pdf 格式,最大 50MB')
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\Select::make('type')
|
||||
->label('文档类型')
|
||||
Forms\Components\Select::make('knowledge_base_id')
|
||||
->label('所属知识库')
|
||||
->relationship('knowledgeBase', 'name')
|
||||
->required()
|
||||
->options([
|
||||
'global' => '全局知识库',
|
||||
'dedicated' => '专用知识库',
|
||||
])
|
||||
->default('global')
|
||||
->reactive()
|
||||
->afterStateUpdated(
|
||||
fn($state, callable $set) =>
|
||||
$state === 'global' ? $set('group_id', null) : null
|
||||
)
|
||||
->helperText('全局知识库所有用户可见,专用知识库仅指定分组可见'),
|
||||
|
||||
Forms\Components\Select::make('group_id')
|
||||
->label('所属分组')
|
||||
->relationship('group', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->required(fn(Forms\Get $get): bool => $get('type') === 'dedicated')
|
||||
->visible(fn(Forms\Get $get): bool => $get('type') === 'dedicated')
|
||||
->helperText('专用知识库必须选择所属分组'),
|
||||
->helperText('选择文档所属的知识库'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -129,26 +113,10 @@ class DocumentResource extends Resource
|
||||
return null;
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('type')
|
||||
->label('文档类型')
|
||||
->badge()
|
||||
->color(fn(string $state): string => match ($state) {
|
||||
'global' => 'success',
|
||||
'dedicated' => 'warning',
|
||||
})
|
||||
->formatStateUsing(fn(string $state): string => match ($state) {
|
||||
'global' => '全局知识库',
|
||||
'dedicated' => '专用知识库',
|
||||
default => $state,
|
||||
})
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('group.name')
|
||||
->label('所属分组')
|
||||
Tables\Columns\TextColumn::make('knowledgeBase.name')
|
||||
->label('所属知识库')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->placeholder('—')
|
||||
->toggleable(),
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('uploader.name')
|
||||
->label('上传者')
|
||||
@@ -195,20 +163,12 @@ class DocumentResource extends Resource
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\SelectFilter::make('type')
|
||||
->label('文档类型')
|
||||
->options([
|
||||
'global' => '全局知识库',
|
||||
'dedicated' => '专用知识库',
|
||||
])
|
||||
->placeholder('全部类型'),
|
||||
|
||||
Tables\Filters\SelectFilter::make('group_id')
|
||||
->label('所属分组')
|
||||
->relationship('group', 'name')
|
||||
Tables\Filters\SelectFilter::make('knowledge_base_id')
|
||||
->label('所属知识库')
|
||||
->relationship('knowledgeBase', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->placeholder('全部分组'),
|
||||
->placeholder('全部知识库'),
|
||||
|
||||
Tables\Filters\SelectFilter::make('uploaded_by')
|
||||
->label('上传者')
|
||||
|
||||
@@ -16,10 +16,6 @@ class CreateDocument extends CreateRecord
|
||||
{
|
||||
$data['uploaded_by'] = Auth::id();
|
||||
|
||||
if ($data['type'] === 'global') {
|
||||
$data['group_id'] = null;
|
||||
}
|
||||
|
||||
if (isset($data['file'])) {
|
||||
$filePath = $data['file'];
|
||||
|
||||
|
||||
@@ -38,10 +38,6 @@ class EditDocument extends EditRecord
|
||||
|
||||
protected function mutateFormDataBeforeSave(array $data): array
|
||||
{
|
||||
if ($data['type'] === 'global') {
|
||||
$data['group_id'] = null;
|
||||
}
|
||||
|
||||
$currentFile = $data['file'] ?? null;
|
||||
|
||||
// 检测文件是否变更:与填充时记录的原始路径比较
|
||||
@@ -62,7 +58,6 @@ class EditDocument extends EditRecord
|
||||
// 重置转换状态,触发重新转换
|
||||
$data['conversion_status'] = 'pending';
|
||||
$data['markdown_path'] = null;
|
||||
$data['markdown_preview'] = null;
|
||||
$data['conversion_error'] = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,24 +114,9 @@ class ViewDocument extends ViewRecord
|
||||
->placeholder('无描述')
|
||||
->columnSpanFull(),
|
||||
|
||||
TextEntry::make('type')
|
||||
->label('文档类型')
|
||||
->badge()
|
||||
->color(fn (string $state): string => match ($state) {
|
||||
'global' => 'success',
|
||||
'dedicated' => 'warning',
|
||||
})
|
||||
->formatStateUsing(fn (string $state): string => match ($state) {
|
||||
'global' => '全局知识库',
|
||||
'dedicated' => '专用知识库',
|
||||
default => $state,
|
||||
}),
|
||||
|
||||
TextEntry::make('group.name')
|
||||
->label('所属分组')
|
||||
->placeholder('—')
|
||||
->visible(fn ($record) => $record->type === 'dedicated'),
|
||||
|
||||
TextEntry::make('knowledgeBase.name')
|
||||
->label('所属知识库'),
|
||||
|
||||
TextEntry::make('uploader.name')
|
||||
->label('上传者'),
|
||||
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\GroupResource\Pages;
|
||||
use App\Filament\Resources\GroupResource\RelationManagers;
|
||||
use App\Models\Group;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class GroupResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Group::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-user-group';
|
||||
|
||||
protected static ?string $navigationLabel = '分组管理';
|
||||
|
||||
protected static ?string $modelLabel = '分组';
|
||||
|
||||
protected static ?string $pluralModelLabel = '分组';
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static ?string $navigationGroup = '权限管理';
|
||||
|
||||
/**
|
||||
* 控制导航菜单是否显示
|
||||
*/
|
||||
public static function shouldRegisterNavigation(): bool
|
||||
{
|
||||
return auth()->user()?->can('group.view') ?? false;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label('分组名称')
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->placeholder('请输入分组名称'),
|
||||
Forms\Components\Textarea::make('description')
|
||||
->label('分组描述')
|
||||
->rows(3)
|
||||
->maxLength(65535)
|
||||
->placeholder('请输入分组描述(可选)')
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('分组名称')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('description')
|
||||
->label('分组描述')
|
||||
->limit(50)
|
||||
->searchable()
|
||||
->toggleable(),
|
||||
Tables\Columns\TextColumn::make('users_count')
|
||||
->label('成员数量')
|
||||
->counts('users')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('创建时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
->label('更新时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\ViewAction::make()
|
||||
->label('查看'),
|
||||
Tables\Actions\EditAction::make()
|
||||
->label('编辑'),
|
||||
Tables\Actions\DeleteAction::make()
|
||||
->label('删除'),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make()
|
||||
->label('批量删除'),
|
||||
]),
|
||||
])
|
||||
->defaultSort('created_at', 'desc');
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
RelationManagers\UsersRelationManager::class,
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListGroups::route('/'),
|
||||
'create' => Pages\CreateGroup::route('/create'),
|
||||
'edit' => Pages\EditGroup::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\GroupResource\Pages;
|
||||
|
||||
use App\Filament\Resources\GroupResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateGroup extends CreateRecord
|
||||
{
|
||||
protected static string $resource = GroupResource::class;
|
||||
|
||||
protected static ?string $title = '创建分组';
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
}
|
||||
|
||||
protected function getCreatedNotificationTitle(): ?string
|
||||
{
|
||||
return '分组创建成功';
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\GroupResource\Pages;
|
||||
|
||||
use App\Filament\Resources\GroupResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditGroup extends EditRecord
|
||||
{
|
||||
protected static string $resource = GroupResource::class;
|
||||
|
||||
protected static ?string $title = '编辑分组';
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->label('删除')
|
||||
->modalHeading('删除分组')
|
||||
->modalDescription('确定要删除此分组吗?此操作无法撤销。')
|
||||
->modalSubmitActionLabel('确认删除')
|
||||
->modalCancelActionLabel('取消'),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getSavedNotificationTitle(): ?string
|
||||
{
|
||||
return '分组更新成功';
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\GroupResource\Pages;
|
||||
|
||||
use App\Filament\Resources\GroupResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListGroups extends ListRecords
|
||||
{
|
||||
protected static string $resource = GroupResource::class;
|
||||
|
||||
protected static ?string $title = '分组列表';
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('创建分组'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\GroupResource\RelationManagers;
|
||||
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class UsersRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'users';
|
||||
|
||||
protected static ?string $title = '分组成员';
|
||||
|
||||
protected static ?string $modelLabel = '用户';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label('用户名称')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Forms\Components\TextInput::make('email')
|
||||
->label('邮箱')
|
||||
->email()
|
||||
->required()
|
||||
->maxLength(255),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('name')
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('用户名称')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('email')
|
||||
->label('邮箱')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('加入时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\AttachAction::make()
|
||||
->label('添加成员')
|
||||
->preloadRecordSelect()
|
||||
->modalHeading('添加分组成员')
|
||||
->modalSubmitActionLabel('添加')
|
||||
->modalCancelActionLabel('取消'),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\DetachAction::make()
|
||||
->label('移除')
|
||||
->modalHeading('移除分组成员')
|
||||
->modalDescription('确定要将此用户从分组中移除吗?')
|
||||
->modalSubmitActionLabel('确认移除')
|
||||
->modalCancelActionLabel('取消'),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DetachBulkAction::make()
|
||||
->label('批量移除')
|
||||
->modalHeading('批量移除分组成员')
|
||||
->modalDescription('确定要将选中的用户从分组中移除吗?')
|
||||
->modalSubmitActionLabel('确认移除')
|
||||
->modalCancelActionLabel('取消'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\GuideResource\Pages;
|
||||
use App\Models\Guide;
|
||||
use App\Models\Terminal;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
@@ -33,6 +32,18 @@ class GuideResource extends Resource
|
||||
return auth()->user()?->can('guide.view') ?? false;
|
||||
}
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user && $user->hasStationRestriction()) {
|
||||
$query->accessibleBy($user);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
@@ -80,17 +91,17 @@ class GuideResource extends Resource
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Forms\Components\Section::make('关联终端')
|
||||
Forms\Components\Section::make('关联线站')
|
||||
->schema([
|
||||
Forms\Components\CheckboxList::make('terminals')
|
||||
->label('适用终端')
|
||||
->relationship('terminals', 'name')
|
||||
Forms\Components\CheckboxList::make('stations')
|
||||
->label('适用线站')
|
||||
->relationship('stations', 'name')
|
||||
->searchable()
|
||||
->bulkToggleable()
|
||||
->helperText('选择此指引适用的终端,未关联终端的指引不会在终端显示')
|
||||
->helperText('选择此指引适用的线站,未关联线站的指引为全局指引')
|
||||
->columns(3),
|
||||
])
|
||||
->description('配置此指引在哪些终端上可见'),
|
||||
->description('不关联任何线站则为全局指引,对所有终端可见'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -147,13 +158,13 @@ class GuideResource extends Resource
|
||||
->counts('pages')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('terminals_count')
|
||||
->label('关联终端')
|
||||
->counts('terminals')
|
||||
Tables\Columns\TextColumn::make('stations_count')
|
||||
->label('关联线站')
|
||||
->counts('stations')
|
||||
->sortable()
|
||||
->badge()
|
||||
->color(fn(int $state): string => $state > 0 ? 'success' : 'gray')
|
||||
->formatStateUsing(fn(int $state): string => $state > 0 ? "{$state} 个" : '未关联'),
|
||||
->color(fn(int $state): string => $state > 0 ? 'info' : 'success')
|
||||
->formatStateUsing(fn(int $state): string => $state > 0 ? "{$state} 个" : '全局'),
|
||||
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('创建时间')
|
||||
|
||||
153
app/Filament/Resources/KnowledgeBaseResource.php
Normal file
153
app/Filament/Resources/KnowledgeBaseResource.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\KnowledgeBaseResource\Pages;
|
||||
use App\Models\KnowledgeBase;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class KnowledgeBaseResource extends Resource
|
||||
{
|
||||
protected static ?string $model = KnowledgeBase::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-book-open';
|
||||
|
||||
protected static ?string $navigationLabel = '知识库管理';
|
||||
|
||||
protected static ?string $modelLabel = '知识库';
|
||||
|
||||
protected static ?string $pluralModelLabel = '知识库';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $navigationGroup = '知识管理';
|
||||
|
||||
public static function getEloquentQuery(): \Illuminate\Database\Eloquent\Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user && $user->hasStationRestriction()) {
|
||||
$query->accessibleBy($user);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label('知识库名称')
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->placeholder('请输入知识库名称'),
|
||||
|
||||
Forms\Components\Select::make('status')
|
||||
->label('状态')
|
||||
->options([
|
||||
'active' => '启用',
|
||||
'inactive' => '停用',
|
||||
])
|
||||
->default('active')
|
||||
->required(),
|
||||
|
||||
Forms\Components\Textarea::make('description')
|
||||
->label('描述')
|
||||
->rows(3)
|
||||
->maxLength(65535)
|
||||
->placeholder('请输入知识库描述(可选)')
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\Select::make('stations')
|
||||
->label('关联线站')
|
||||
->relationship('stations', 'name')
|
||||
->multiple()
|
||||
->searchable()
|
||||
->preload()
|
||||
->helperText('选择知识库对哪些线站可用')
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('知识库名称')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\BadgeColumn::make('status')
|
||||
->label('状态')
|
||||
->colors([
|
||||
'success' => 'active',
|
||||
'danger' => 'inactive',
|
||||
])
|
||||
->formatStateUsing(fn(string $state): string => match ($state) {
|
||||
'active' => '启用',
|
||||
'inactive' => '停用',
|
||||
default => $state,
|
||||
})
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('stations_count')
|
||||
->label('关联线站')
|
||||
->counts('stations')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('documents_count')
|
||||
->label('文档数量')
|
||||
->counts('documents')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('创建时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
->label('更新时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\SelectFilter::make('status')
|
||||
->label('状态')
|
||||
->options([
|
||||
'active' => '启用',
|
||||
'inactive' => '停用',
|
||||
]),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make()
|
||||
->label('编辑'),
|
||||
Tables\Actions\DeleteAction::make()
|
||||
->label('删除'),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make()
|
||||
->label('批量删除'),
|
||||
]),
|
||||
])
|
||||
->defaultSort('created_at', 'desc');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListKnowledgeBases::route('/'),
|
||||
'create' => Pages\CreateKnowledgeBase::route('/create'),
|
||||
'edit' => Pages\EditKnowledgeBase::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\KnowledgeBaseResource\Pages;
|
||||
|
||||
use App\Filament\Resources\KnowledgeBaseResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateKnowledgeBase extends CreateRecord
|
||||
{
|
||||
protected static string $resource = KnowledgeBaseResource::class;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\KnowledgeBaseResource\Pages;
|
||||
|
||||
use App\Filament\Resources\KnowledgeBaseResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditKnowledgeBase extends EditRecord
|
||||
{
|
||||
protected static string $resource = KnowledgeBaseResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->label('删除'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\KnowledgeBaseResource\Pages;
|
||||
|
||||
use App\Filament\Resources\KnowledgeBaseResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListKnowledgeBases extends ListRecords
|
||||
{
|
||||
protected static string $resource = KnowledgeBaseResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('新建知识库'),
|
||||
];
|
||||
}
|
||||
}
|
||||
130
app/Filament/Resources/StationResource.php
Normal file
130
app/Filament/Resources/StationResource.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\StationResource\Pages;
|
||||
use App\Models\Station;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class StationResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Station::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-building-office';
|
||||
|
||||
protected static ?string $navigationLabel = '线站管理';
|
||||
|
||||
protected static ?string $modelLabel = '线站';
|
||||
|
||||
protected static ?string $pluralModelLabel = '线站';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $navigationGroup = '业务管理';
|
||||
|
||||
public static function shouldRegisterNavigation(): bool
|
||||
{
|
||||
return auth()->user()?->can('station.view') ?? false;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label('线站名称')
|
||||
->required()
|
||||
->unique(ignoreRecord: true)
|
||||
->maxLength(255)
|
||||
->placeholder('例如: BL02U1'),
|
||||
|
||||
Forms\Components\Textarea::make('description')
|
||||
->label('线站描述')
|
||||
->rows(3)
|
||||
->maxLength(65535)
|
||||
->placeholder('请输入线站描述(可选)')
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\Select::make('users')
|
||||
->label('关联用户')
|
||||
->relationship('users', 'name')
|
||||
->multiple()
|
||||
->searchable()
|
||||
->preload()
|
||||
->helperText('关联到此线站的用户只能看到与本线站相关的资源')
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\Select::make('guides')
|
||||
->label('关联指引')
|
||||
->relationship('guides', 'name')
|
||||
->multiple()
|
||||
->searchable()
|
||||
->preload()
|
||||
->helperText('选择此线站可用的操作指引')
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('线站名称')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('description')
|
||||
->label('描述')
|
||||
->limit(50)
|
||||
->toggleable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('users_count')
|
||||
->label('用户数量')
|
||||
->counts('users')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('terminals_count')
|
||||
->label('终端数量')
|
||||
->counts('terminals')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('knowledge_bases_count')
|
||||
->label('知识库数量')
|
||||
->counts('knowledgeBases')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('创建时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make()
|
||||
->label('编辑'),
|
||||
Tables\Actions\DeleteAction::make()
|
||||
->label('删除'),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make()
|
||||
->label('批量删除'),
|
||||
]),
|
||||
])
|
||||
->defaultSort('name');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListStations::route('/'),
|
||||
'create' => Pages\CreateStation::route('/create'),
|
||||
'edit' => Pages\EditStation::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\StationResource\Pages;
|
||||
|
||||
use App\Filament\Resources\StationResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateStation extends CreateRecord
|
||||
{
|
||||
protected static string $resource = StationResource::class;
|
||||
}
|
||||
20
app/Filament/Resources/StationResource/Pages/EditStation.php
Normal file
20
app/Filament/Resources/StationResource/Pages/EditStation.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\StationResource\Pages;
|
||||
|
||||
use App\Filament\Resources\StationResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditStation extends EditRecord
|
||||
{
|
||||
protected static string $resource = StationResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->label('删除'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\StationResource\Pages;
|
||||
|
||||
use App\Filament\Resources\StationResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListStations extends ListRecords
|
||||
{
|
||||
protected static string $resource = StationResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('新建线站'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,18 @@ class TerminalResource extends Resource
|
||||
return auth()->user()?->can('terminal.view') ?? false;
|
||||
}
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user && $user->hasStationRestriction()) {
|
||||
$query->whereIn('station_id', $user->getAccessibleStationIds());
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
@@ -77,11 +89,13 @@ class TerminalResource extends Resource
|
||||
'regex' => 'MAC地址格式不正确,应为 AA:BB:CC:DD:EE:FF',
|
||||
]),
|
||||
|
||||
Forms\Components\TextInput::make('station_id')
|
||||
->label('线站ID')
|
||||
->maxLength(50)
|
||||
->placeholder('例如: BL02U1')
|
||||
->helperText('关联的光束线/线站标识'),
|
||||
Forms\Components\Select::make('station_id')
|
||||
->label('所属线站')
|
||||
->relationship('station', 'name')
|
||||
->searchable()
|
||||
->preload()
|
||||
->placeholder('未绑定')
|
||||
->helperText('终端所属的线站'),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
@@ -131,44 +145,6 @@ class TerminalResource extends Resource
|
||||
->columns(2)
|
||||
->description('配置终端的语音唤醒能力'),
|
||||
|
||||
Forms\Components\Section::make('指引关联')
|
||||
->schema([
|
||||
Forms\Components\Repeater::make('guideAssociations')
|
||||
->label('关联指引')
|
||||
->relationship('guides')
|
||||
->schema([
|
||||
Forms\Components\Select::make('id')
|
||||
->label('指引')
|
||||
->options(\App\Models\Guide::where('status', 'published')->pluck('name', 'id'))
|
||||
->required()
|
||||
->searchable()
|
||||
->distinct()
|
||||
->disableOptionsWhenSelectedInSiblingRepeaterItems()
|
||||
->helperText('选择要关联的指引'),
|
||||
|
||||
Forms\Components\TextInput::make('priority')
|
||||
->label('优先级')
|
||||
->numeric()
|
||||
->default(0)
|
||||
->required()
|
||||
->minValue(0)
|
||||
->helperText('数字越小优先级越高,0为最高优先级'),
|
||||
])
|
||||
->columns(2)
|
||||
->reorderable()
|
||||
->reorderableWithButtons()
|
||||
->addActionLabel('添加指引')
|
||||
->reorderableWithDragAndDrop(false)
|
||||
->itemLabel(
|
||||
fn(array $state): ?string =>
|
||||
\App\Models\Guide::find($state['id'])?->name ?? '未选择'
|
||||
)
|
||||
->collapsed()
|
||||
->collapsible()
|
||||
->helperText('可以关联多个指引,并设置优先级。拖动或使用按钮调整顺序。'),
|
||||
])
|
||||
->description('配置终端可以访问的操作指引及其优先级'),
|
||||
|
||||
Forms\Components\Section::make('AI提示词配置')
|
||||
->schema([
|
||||
Forms\Components\Grid::make(3)
|
||||
@@ -177,21 +153,18 @@ class TerminalResource extends Resource
|
||||
->label('提示词模板')
|
||||
->language('markdown')
|
||||
->fontSize('14px')
|
||||
->helperText('编辑AI提示词模板,支持使用占位符 {station_id}, {user}, {time}(由HMI端替换)')
|
||||
->helperText('编辑AI提示词模板,可用占位符: {station_name} {terminal_code} {terminal_name} {user} {time}')
|
||||
->placeholderText('请输入AI提示词模板...')
|
||||
->disablePreview()
|
||||
->columnSpan(2),
|
||||
|
||||
Forms\Components\Grid::make(1)
|
||||
->schema([
|
||||
Forms\Components\Placeholder::make('variable_helper')
|
||||
->label('变量参考')
|
||||
->content(fn() => view('filament.components.prompt-variable-helper')),
|
||||
])
|
||||
Forms\Components\Placeholder::make('variable_helper')
|
||||
->label('可用占位符')
|
||||
->content('`{station_name}` 线站名称 · `{terminal_code}` 终端编码 · `{terminal_name}` 终端名称 · `{user}` 用户名称 · `{time}` 当前时间')
|
||||
->columnSpan(1),
|
||||
]),
|
||||
])
|
||||
->description('配置终端的AI提示词模板,占位符由HMI端替换')
|
||||
->description('配置终端的AI提示词模板')
|
||||
->collapsible(),
|
||||
|
||||
Forms\Components\Section::make('状态信息')
|
||||
@@ -243,8 +216,8 @@ class TerminalResource extends Resource
|
||||
->copyable()
|
||||
->placeholder('未设置'),
|
||||
|
||||
Tables\Columns\TextColumn::make('station_id')
|
||||
->label('线站ID')
|
||||
Tables\Columns\TextColumn::make('station.name')
|
||||
->label('所属线站')
|
||||
->sortable()
|
||||
->placeholder('未绑定'),
|
||||
|
||||
@@ -299,7 +272,7 @@ class TerminalResource extends Resource
|
||||
])
|
||||
->defaultSort('created_at', 'desc')
|
||||
->groups([
|
||||
Tables\Grouping\Group::make('station_id')
|
||||
Tables\Grouping\Group::make('station.name')
|
||||
->label('按线站分组')
|
||||
->collapsible(),
|
||||
Tables\Grouping\Group::make('is_online')
|
||||
|
||||
@@ -37,8 +37,8 @@ class ViewTerminal extends ViewRecord
|
||||
->label('IP地址')
|
||||
->copyable()
|
||||
->placeholder('未设置'),
|
||||
Infolists\Components\TextEntry::make('station_id')
|
||||
->label('线站ID')
|
||||
Infolists\Components\TextEntry::make('station.name')
|
||||
->label('所属线站')
|
||||
->placeholder('未绑定'),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
@@ -29,14 +29,27 @@ class UserResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = '权限管理';
|
||||
|
||||
/**
|
||||
* 控制导航菜单是否显示
|
||||
*/
|
||||
public static function shouldRegisterNavigation(): bool
|
||||
{
|
||||
return auth()->user()?->can('user.view') ?? false;
|
||||
}
|
||||
|
||||
public static function getEloquentQuery(): \Illuminate\Database\Eloquent\Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user && $user->hasStationRestriction()) {
|
||||
$stationIds = $user->getAccessibleStationIds();
|
||||
$query->where(function ($q) use ($stationIds) {
|
||||
$q->whereDoesntHave('stations')
|
||||
->orWhereHas('stations', fn ($sq) => $sq->whereIn('stations.id', $stationIds));
|
||||
});
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限分组标签页
|
||||
*/
|
||||
@@ -49,7 +62,6 @@ class UserResource extends Resource
|
||||
'activity-log' => ['name' => '操作日志', 'icon' => 'heroicon-o-clipboard-document-list'],
|
||||
'terminal' => ['name' => '终端管理', 'icon' => 'heroicon-o-computer-desktop'],
|
||||
'guide' => ['name' => '操作指引', 'icon' => 'heroicon-o-book-open'],
|
||||
'group' => ['name' => '分组管理', 'icon' => 'heroicon-o-user-group'],
|
||||
'user' => ['name' => '用户管理', 'icon' => 'heroicon-o-users'],
|
||||
'role' => ['name' => '角色管理', 'icon' => 'heroicon-o-shield-check'],
|
||||
];
|
||||
@@ -140,15 +152,15 @@ class UserResource extends Resource
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Forms\Components\Section::make('分组与角色')
|
||||
Forms\Components\Section::make('线站与角色')
|
||||
->schema([
|
||||
Forms\Components\Select::make('groups')
|
||||
->label('所属分组')
|
||||
Forms\Components\Select::make('stations')
|
||||
->label('关联线站')
|
||||
->multiple()
|
||||
->relationship('groups', 'name')
|
||||
->relationship('stations', 'name')
|
||||
->preload()
|
||||
->placeholder('请选择用户所属的分组')
|
||||
->helperText('用户可以属于多个分组'),
|
||||
->placeholder('不关联线站则可访问全部资源')
|
||||
->helperText('关联线站后用户只能看到对应线站的资源'),
|
||||
Forms\Components\Select::make('roles')
|
||||
->label('角色')
|
||||
->multiple()
|
||||
@@ -172,7 +184,7 @@ class UserResource extends Resource
|
||||
->dehydrateStateUsing(function ($state, $get) {
|
||||
// 收集所有模块的权限
|
||||
$allPermissions = [];
|
||||
$modules = ['document', 'system-setting', 'activity-log', 'terminal', 'guide', 'group', 'user', 'role'];
|
||||
$modules = ['document', 'system-setting', 'activity-log', 'terminal', 'guide', 'user', 'role'];
|
||||
|
||||
foreach ($modules as $module) {
|
||||
$modulePermissions = $get("permissions_{$module}") ?? [];
|
||||
@@ -222,7 +234,7 @@ class UserResource extends Resource
|
||||
})
|
||||
->searchable()
|
||||
->toggleable(),
|
||||
Tables\Columns\TextColumn::make('groups.name')
|
||||
Tables\Columns\TextColumn::make('stations.name')
|
||||
->label('所属分组')
|
||||
->badge()
|
||||
->searchable()
|
||||
@@ -300,7 +312,6 @@ class UserResource extends Resource
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
RelationManagers\GroupsRelationManager::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\UserResource\RelationManagers;
|
||||
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class GroupsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'groups';
|
||||
|
||||
protected static ?string $title = '用户分组';
|
||||
|
||||
protected static ?string $modelLabel = '分组';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label('分组名称')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Forms\Components\Textarea::make('description')
|
||||
->label('分组描述')
|
||||
->rows(3)
|
||||
->maxLength(65535),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('name')
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('分组名称')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('description')
|
||||
->label('分组描述')
|
||||
->limit(50)
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('加入时间')
|
||||
->dateTime('Y-m-d H:i:s')
|
||||
->sortable(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\AttachAction::make()
|
||||
->label('添加分组')
|
||||
->preloadRecordSelect()
|
||||
->modalHeading('添加用户到分组')
|
||||
->modalSubmitActionLabel('添加')
|
||||
->modalCancelActionLabel('取消'),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\DetachAction::make()
|
||||
->label('移除')
|
||||
->modalHeading('移除用户分组')
|
||||
->modalDescription('确定要将此用户从该分组中移除吗?')
|
||||
->modalSubmitActionLabel('确认移除')
|
||||
->modalCancelActionLabel('取消'),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DetachBulkAction::make()
|
||||
->label('批量移除')
|
||||
->modalHeading('批量移除用户分组')
|
||||
->modalDescription('确定要将此用户从选中的分组中移除吗?')
|
||||
->modalSubmitActionLabel('确认移除')
|
||||
->modalCancelActionLabel('取消'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user