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