Laravel10/FilamentPHP3:点击通知内链接标记通知为已读方案
解决FilamentPHP 3中点击通知链接自动标记已读并移除的问题
问题场景
在Laravel 10 + FilamentPHP 3应用中,前端用户完成操作后会向管理员发送包含后台表单跳转链接的通知。目前点击链接可正常跳转,但通知仍停留在右上角列表中,需手动点击关闭图标才会消失,需要实现点击链接时自动将通知标记为已读并移除。
解决方案
方案一:利用Filament通知内置Action(推荐)
最贴合Filament设计规范的方式是放弃在通知body中直接嵌入HTML链接,改用Filament通知的action方法添加操作按钮,Filament会自动处理点击后的通知已读标记:
修改事件监听器中的Filament通知发送代码:
\Filament\Notifications\Notification::make() ->title('Quiz completed by user') ->body("Hi {$manager->name}, \n job seeker {$userQuizRequest->jobSeeker->name} at \"Quizzes\" site ran \"HTML category\" quiz. \n\nYou have received this notification as you are manager of \"Quizzes\" \n\nBest Regards,\nSupport of Quizzes Team") ->info() ->action('View Request', function () use ($userQuizRequest) { // 跳转到对应的编辑页面,替换为你的实际路由 return redirect()->route('filament.service-owner.resources.user-quiz-requests.edit', ['record' => $userQuizRequest->id]); }) ->sendToDatabase(users: [$tempUser]);
这种方式下,管理员点击「View Request」按钮时,系统会自动将该通知标记为已读并从列表中移除,无需额外编写前端代码。
方案二:自定义链接+前端JS处理(兼容现有HTML链接场景)
如果必须保留body中的HTML链接,可通过以下步骤实现需求:
1. 给链接附加通知ID
修改事件监听器代码,先保存通知获取ID,再将ID注入到链接的自定义属性中:
$tempUser = User::factory()->make([ 'id' => $manager->id, 'name' => $manager->name, 'email' => $manager->email, ]); // 创建并发送通知到数据库 $filamentNotification = \Filament\Notifications\Notification::make() ->title('Quiz completed by user') ->body($content) ->info(); $databaseNotification = $filamentNotification->sendToDatabase(users: [$tempUser])->first(); // 给链接添加data-notification-id属性 $updatedBody = str_replace( '<a href="', '<a data-notification-id="' . $databaseNotification->id . '" href="', $databaseNotification->data['body'] ); // 更新通知的body内容 $databaseNotification->update([ 'data' => array_merge($databaseNotification->data, ['body' => $updatedBody]) ]);
2. 添加前端点击事件处理
在Filament自定义脚本文件(如resources/js/filament.js)中添加监听逻辑:
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('click', (e) => { const targetLink = e.target.closest('a[data-notification-id]'); if (!targetLink) return; const notificationId = targetLink.dataset.notificationId; const csrfToken = document.querySelector('meta[name="csrf-token"]').content; // 调用Filament标记已读接口 fetch(`/admin/notifications/${notificationId}/mark-as-read`, { method: 'POST', headers: { 'X-CSRF-TOKEN': csrfToken, 'Accept': 'application/json' } }).then(() => { // 移除通知元素 const notificationElement = targetLink.closest('.filament-notifications-notification'); if (notificationElement) notificationElement.remove(); }).catch(err => console.error('标记通知已读失败:', err)); }); });
3. 确认路由可用性
Filament默认已注册通知标记已读的路由,若路由不存在,可手动在routes/web.php中添加:
use Filament\Http\Controllers\NotificationsController; Route::post('/admin/notifications/{notification}/mark-as-read', [NotificationsController::class, 'markAsRead']) ->middleware(['auth']) ->name('filament.notifications.mark-as-read');
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

