优化 刷新页面不在重复播报 离开和登录提示
This commit is contained in:
@@ -175,17 +175,17 @@ class ChatController extends Controller
|
||||
];
|
||||
|
||||
// 当会员等级带有专属主题时,把横幅与特效字段并入系统消息,供前端展示豪华进场效果。
|
||||
if (! empty($vipPresencePayload)) {
|
||||
$generalWelcomeMsg = array_merge($generalWelcomeMsg, $vipPresencePayload);
|
||||
$initialPresenceTheme = $vipPresencePayload;
|
||||
}
|
||||
if (! empty($vipPresencePayload)) {
|
||||
$generalWelcomeMsg = array_merge($generalWelcomeMsg, $vipPresencePayload);
|
||||
$initialPresenceTheme = $vipPresencePayload;
|
||||
}
|
||||
|
||||
// 把当前这次进房生成的欢迎消息带回前端,确保用户自己也一定能看到。
|
||||
$initialWelcomeMessage = $generalWelcomeMsg;
|
||||
// 把当前这次进房生成的欢迎消息带回前端,确保用户自己也一定能看到。
|
||||
$initialWelcomeMessage = $generalWelcomeMsg;
|
||||
|
||||
$this->chatState->pushMessage($id, $generalWelcomeMsg);
|
||||
// 修复:之前使用了 ->toOthers() 导致自己看不到自己的进场提示
|
||||
broadcast(new MessageSent($id, $generalWelcomeMsg));
|
||||
$this->chatState->pushMessage($id, $generalWelcomeMsg);
|
||||
// 修复:之前使用了 ->toOthers() 导致自己看不到自己的进场提示
|
||||
broadcast(new MessageSent($id, $generalWelcomeMsg));
|
||||
|
||||
// 会员专属特效需要单独广播给其他在线成员,自己则在页面初始化后本地补播。
|
||||
if (! empty($vipPresencePayload['presence_effect'])) {
|
||||
@@ -547,7 +547,7 @@ class ChatController extends Controller
|
||||
if ($bonusJjb > 0) {
|
||||
$bonusParts[] = "+金币{$bonusJjb}";
|
||||
}
|
||||
|
||||
|
||||
$eventContent = $autoEvent->renderText($user->username);
|
||||
if (! empty($bonusParts)) {
|
||||
$eventContent .= '('.$user->vipName().'追加:'.implode(',', $bonusParts).')';
|
||||
@@ -600,6 +600,24 @@ class ChatController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理登录失效后的离场清理。
|
||||
*
|
||||
* 该接口通过临时签名 URL 调用,即使会话已过期也能安全完成离场结算。
|
||||
*/
|
||||
public function expiredLeave(int $id, int $user): JsonResponse
|
||||
{
|
||||
$expiredUser = User::find($user);
|
||||
|
||||
if (! $expiredUser) {
|
||||
return response()->json(['status' => 'error'], 404);
|
||||
}
|
||||
|
||||
$this->dispatchImmediateLeave($id, $expiredUser, '登录失效离开了房间');
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有房间的在线人数,供右侧房间面板轮询使用。
|
||||
*
|
||||
@@ -642,13 +660,8 @@ class ChatController extends Controller
|
||||
$isExplicit = strval($request->query('explicit')) === '1';
|
||||
|
||||
if ($isExplicit) {
|
||||
// 人工显式点击“离开”,不再进行浏览器刷新的防抖,直接同步执行清算和播报。
|
||||
// 这对本地没有开启 Queue Worker 的环境尤为重要,能保证大家立刻看到消息。
|
||||
// 为了防止 ProcessUserLeave 中的时间对比失败,我们直接删掉 join_time 表示彻底离线。
|
||||
\Illuminate\Support\Facades\Redis::del("room:{$id}:join_time:{$user->username}");
|
||||
|
||||
$job = new \App\Jobs\ProcessUserLeave($id, clone $user, $leaveTime);
|
||||
dispatch_sync($job);
|
||||
// 人工显式点击“离开”时,立即同步执行清算和播报。
|
||||
$this->dispatchImmediateLeave($id, $user, '主动离开了房间');
|
||||
} else {
|
||||
// 不立刻执行离线逻辑,而是给个 3 秒的防抖延迟
|
||||
// 这样如果用户只是刷新页面,很快在 init 中又会重新加入房间(记录的 join_time 会大于当前 leave 时的 leaveTime)
|
||||
@@ -659,6 +672,17 @@ class ChatController extends Controller
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即执行离场清理,并跳过刷新防抖逻辑。
|
||||
*/
|
||||
private function dispatchImmediateLeave(int $id, User $user, string $outInfo): void
|
||||
{
|
||||
Redis::del("room:{$id}:join_time:{$user->username}");
|
||||
|
||||
$job = new \App\Jobs\ProcessUserLeave($id, clone $user, microtime(true), $outInfo);
|
||||
dispatch_sync($job);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用头像列表(返回 JSON)
|
||||
* 扫描 /public/images/headface/ 目录,返回所有可用头像文件名
|
||||
|
||||
@@ -30,7 +30,8 @@ class ProcessUserLeave implements ShouldQueue
|
||||
public function __construct(
|
||||
public int $roomId,
|
||||
public User $user,
|
||||
public float $leaveTime
|
||||
public float $leaveTime,
|
||||
public string $outInfo = '正常退出了房间',
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ class ProcessUserLeave implements ShouldQueue
|
||||
// 记录退出时间和退出信息
|
||||
$this->user->update([
|
||||
'out_time' => now(),
|
||||
'out_info' => '正常退出了房间',
|
||||
'out_info' => $this->outInfo,
|
||||
]);
|
||||
|
||||
// 关闭该用户尚未结束的在职登录记录(结算在线时长)
|
||||
@@ -60,41 +61,25 @@ class ProcessUserLeave implements ShouldQueue
|
||||
|
||||
// 2. 发送离场播报
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
|
||||
[$leaveText, $color] = $broadcast->buildLeaveBroadcast($this->user);
|
||||
$vipPresencePayload = $broadcast->buildVipPresencePayload($this->user, 'leave');
|
||||
$leaveMsg = [
|
||||
'id' => $chatState->nextMessageId($this->roomId),
|
||||
'room_id' => $this->roomId,
|
||||
'from_user' => '进出播报',
|
||||
'to_user' => '大家',
|
||||
'content' => "<span style=\"color: {$color}; font-weight: bold;\">{$leaveText}</span>",
|
||||
'is_secret' => false,
|
||||
'font_color' => $color,
|
||||
'action' => empty($vipPresencePayload) ? 'system_welcome' : 'vip_presence',
|
||||
'welcome_user' => $this->user->username,
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
if ($this->user->user_level >= $superLevel) {
|
||||
// 管理员离场:系统公告
|
||||
$leaveMsg = [
|
||||
'id' => $chatState->nextMessageId($this->roomId),
|
||||
'room_id' => $this->roomId,
|
||||
'from_user' => '系统公告',
|
||||
'to_user' => '大家',
|
||||
'content' => "👋 管理员 【{$this->user->username}】 已离开聊天室。",
|
||||
'is_secret' => false,
|
||||
'font_color' => '#b91c1c',
|
||||
'action' => 'admin_welcome',
|
||||
'welcome_user' => $this->user->username,
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
} else {
|
||||
[$leaveText, $color] = $broadcast->buildLeaveBroadcast($this->user);
|
||||
$vipPresencePayload = $broadcast->buildVipPresencePayload($this->user, 'leave');
|
||||
$leaveMsg = [
|
||||
'id' => $chatState->nextMessageId($this->roomId),
|
||||
'room_id' => $this->roomId,
|
||||
'from_user' => '进出播报',
|
||||
'to_user' => '大家',
|
||||
'content' => "<span style=\"color: {$color}; font-weight: bold;\">{$leaveText}</span>",
|
||||
'is_secret' => false,
|
||||
'font_color' => $color,
|
||||
'action' => empty($vipPresencePayload) ? 'system_welcome' : 'vip_presence',
|
||||
'welcome_user' => $this->user->username,
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
// 会员离场时,把横幅与特效信息挂到消息体,前端才能展示专属离场效果。
|
||||
if (! empty($vipPresencePayload)) {
|
||||
$leaveMsg = array_merge($leaveMsg, $vipPresencePayload);
|
||||
}
|
||||
// 会员离场时,把横幅与特效信息挂到消息体,前端才能展示专属离场效果。
|
||||
if (! empty($vipPresencePayload)) {
|
||||
$leaveMsg = array_merge($leaveMsg, $vipPresencePayload);
|
||||
}
|
||||
|
||||
// 将播报存入 Redis 历史及广播
|
||||
|
||||
Reference in New Issue
Block a user