结婚/婚礼/离婚通知持久化:新增事件监听器自动写入聊天消息数据库,用户重新登录后可在历史记录中看到通知

This commit is contained in:
2026-03-01 19:16:27 +08:00
parent eefdae93fe
commit 68c4ca7a96
2 changed files with 146 additions and 3 deletions

View File

@@ -0,0 +1,131 @@
<?php
/**
* 文件功能:婚姻系统消息监听器
*
* 监听 MarriageAccepted / WeddingCelebration / MarriageDivorced 三个事件,
* 自动向聊天室推送并持久化系统消息(写入 Redis 缓存 + 落库 messages 表),
* 使得用户重新登录时可在历史记录中看到这些通知。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Listeners;
use App\Events\MarriageAccepted;
use App\Events\MarriageDivorced;
use App\Events\WeddingCelebration;
use App\Jobs\SaveMessageJob;
use App\Services\ChatStateService;
use Illuminate\Events\Dispatcher;
class SaveMarriageSystemMessage
{
/** 固定使用房间 1大厅。 */
private const ROOM_ID = 1;
public function __construct(
private readonly ChatStateService $chatState,
) {}
/**
* 注册所有监听的事件。
*/
public function subscribe(Dispatcher $events): void
{
$events->listen(MarriageAccepted::class, [static::class, 'onMarriageAccepted']);
$events->listen(WeddingCelebration::class, [static::class, 'onWeddingCelebration']);
$events->listen(MarriageDivorced::class, [static::class, 'onMarriageDivorced']);
}
/**
* 结婚成功 向全频道追加系统消息。
*/
public function onMarriageAccepted(MarriageAccepted $event): void
{
$marriage = $event->marriage;
$marriage->loadMissing(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon']);
$userName = $marriage->user?->username ?? '??';
$partnerName = $marriage->partner?->username ?? '??';
$ring = $marriage->ringItem?->name ?? '爱情之戒';
$content = "💍 喜讯!【{$userName}】与【{$partnerName}】在 {$ring} 的见证下正式结为伴侣,祝新婚快乐!";
$this->pushAndSave($content, '#ec4899');
}
/**
* 婚礼庆典触发 向全频道追加婚礼公告消息。
*/
public function onWeddingCelebration(WeddingCelebration $event): void
{
$ceremony = $event->ceremony;
$marriage = $event->marriage;
$marriage->loadMissing(['user:id,username', 'partner:id,username']);
$ceremony->loadMissing('tier');
$userName = $marriage->user?->username ?? '??';
$partnerName = $marriage->partner?->username ?? '??';
$tierName = $ceremony->tier?->name ?? '婚礼';
$tierIcon = $ceremony->tier?->icon ?? '🎊';
$amount = number_format((int) $ceremony->total_amount);
$content = "{$tierIcon}{$userName}】与【{$partnerName}】举办了【{$tierName}】婚礼大典!"
."总计 🪙{$amount} 金币红包已向全场分发,快去领取吧!";
$this->pushAndSave($content, '#f59e0b');
}
/**
* 离婚完成 向全频道追加离婚公告消息。
*/
public function onMarriageDivorced(MarriageDivorced $event): void
{
$marriage = $event->marriage;
$marriage->loadMissing(['user:id,username', 'partner:id,username']);
$userName = $marriage->user?->username ?? '??';
$partnerName = $marriage->partner?->username ?? '??';
$typeLabel = match ($marriage->divorce_type) {
'forced' => '强制离婚',
'auto' => '超时自动离婚',
'admin' => '管理员强制解除',
default => '协议离婚',
};
$content = "💔 【{$userName}】与【{$partnerName}】已{$typeLabel},缘分已尽,各奔东西。";
$this->pushAndSave($content, '#6b7280');
}
/**
* 将系统消息推入 Redis 缓存并分发 SaveMessageJob 落库。
*
* @param string $content 消息正文
* @param string $fontColor 字体颜色
*/
private function pushAndSave(string $content, string $fontColor): void
{
$msg = [
'id' => $this->chatState->nextMessageId(self::ROOM_ID),
'room_id' => self::ROOM_ID,
'from_user' => '系统传音',
'to_user' => '大家',
'content' => $content,
'is_secret' => false,
'font_color' => $fontColor,
'action' => '大声宣告',
'sent_at' => now()->toDateTimeString(),
];
// 推入 Redis当前在线用户的 polling 会取到)
$this->chatState->pushMessage(self::ROOM_ID, $msg);
// 落库(离线用户下次登录可在历史消息中看到)
SaveMessageJob::dispatch($msg);
}
}

View File

@@ -1,11 +1,20 @@
<?php
/**
* 文件功能:应用服务提供者
*
* 负责注册和引导应用级服务:自定义 SMTP 配置动态加载、
* 婚姻系统消息事件订阅者注册等。
*/
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Listeners\SaveMarriageSystemMessage;
use App\Models\Sysparam;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
@@ -22,11 +31,14 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
// 注册婚姻系统消息订阅者(结婚/婚礼/离婚通知写入聊天历史)
Event::subscribe(SaveMarriageSystemMessage::class);
// 动态加载自定义 SMTP 配置 (如果有数据库则执行)
try {
if (Schema::hasTable('sysparam')) {
$smtpConfig = Sysparam::where('alias', 'like', 'smtp_%')->pluck('body', 'alias');
if ($smtpConfig->isNotEmpty() && $smtpConfig->get('smtp_host')) {
Config::set('mail.default', 'smtp');
Config::set('mail.mailers.smtp', [
@@ -36,7 +48,7 @@ class AppServiceProvider extends ServiceProvider
'encryption' => $smtpConfig->get('smtp_encryption', 'ssl'),
'username' => $smtpConfig->get('smtp_username'),
'password' => $smtpConfig->get('smtp_password'),
'timeout' => 10,
'timeout' => 10,
'local_domain' => env('MAIL_EHLO_DOMAIN'),
]);