label('预览 Markdown') ->icon('heroicon-o-eye') ->color('info') ->visible(fn (): bool => $this->record->conversion_status === 'completed') ->url(fn (): string => route('documents.preview', $this->record)) ->openUrlInNewTab() ->tooltip(fn (): ?string => $this->record->conversion_status !== 'completed' ? '文档尚未完成转换' : null ), Actions\Action::make('download') ->label('下载文档') ->icon('heroicon-o-arrow-down-tray') ->color('success') ->action(function () { $documentService = app(DocumentService::class); $user = auth()->user(); try { // 记录下载日志 $documentService->logDownload($this->record, $user); // 返回文件下载响应 return $documentService->downloadDocument($this->record, $user); } catch (\Exception $e) { Notification::make() ->danger() ->title('下载失败') ->body($e->getMessage()) ->send(); return null; } }), Actions\EditAction::make() ->label('编辑'), Actions\DeleteAction::make() ->label('删除'), ]; } public function infolist(Infolist $infolist): Infolist { return $infolist ->schema([ Section::make('文档信息') ->schema([ TextEntry::make('title') ->label('文档标题') ->size(TextEntry\TextEntrySize::Large) ->weight('bold'), TextEntry::make('description') ->label('文档描述') ->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('uploader.name') ->label('上传者'), TextEntry::make('file_name') ->label('文件名'), TextEntry::make('file_size') ->label('文件大小') ->formatStateUsing(fn ($state): string => DocumentResource::formatFileSize($state)), TextEntry::make('created_at') ->label('上传时间') ->dateTime('Y年m月d日 H:i:s'), TextEntry::make('updated_at') ->label('更新时间') ->dateTime('Y年m月d日 H:i:s'), ]) ->columns(2), Section::make('文档预览') ->schema([ ViewEntry::make('preview') ->label('') ->view('filament.resources.document.preview') ->viewData([ 'document' => $this->record, ]), ]) ->collapsible() ->collapsed(false), ]); } }