新增聊天室刷新同步与全员刷新功能

This commit is contained in:
2026-04-21 17:14:12 +08:00
parent c209221bad
commit fed51dda18
13 changed files with 425 additions and 9 deletions
+3 -1
View File
@@ -74,7 +74,8 @@
chatBotEnabled: {{ $chatbotEnabledState ? 'true' : 'false' }},
botUser: @json($botUserData),
hasPosition: {{ Auth::user()->activePosition || Auth::user()->user_level >= $superLevel ? 'true' : 'false' }},
hasRoomManagementPermission: {{ ! empty($hasRoomManagementPermission) ? 'true' : 'false' }},
hasRoomManagementPermission: {{ (! empty($hasRoomManagementPermission) || Auth::id() === 1) ? 'true' : 'false' }},
isSiteOwner: {{ Auth::id() === 1 ? 'true' : 'false' }},
positionPermissions: @json($positionPermissions),
positionPermissionMap: @json($roomPermissionMap ?? []),
@php
@@ -98,6 +99,7 @@
revokeUrl: "{{ route('chat.appoint.revoke') }}",
rewardUrl: "{{ route('command.reward') }}",
rewardQuotaUrl: "{{ route('command.reward_quota') }}",
refreshAllUrl: "{{ route('command.refresh_all') }}",
chatPreferencesUrl: "{{ route('user.update_chat_preferences') }}",
userJjb: {{ (int) $user->jjb }}, // 当前用户金币(求婚前金额预检查用)
myGold: {{ (int) $user->jjb }}, // 赠金币面板显示余额用(赠送成功后前端更新)
@@ -181,7 +181,7 @@ $welcomeMessages = [
</div>
@endif
@if ($canPublicBroadcast || $canClearScreen || $canSendRedPacket || $canManageLossCover)
@if ($canPublicBroadcast || $canClearScreen || $canSendRedPacket || $canManageLossCover || Auth::id() === 1)
<div style="font-size:10px;color:#9a3412;padding:10px 2px 6px;">聊天室管理</div>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;">
@if ($canPublicBroadcast)
@@ -200,6 +200,10 @@ $welcomeMessages = [
<button type="button" onclick="runAdminAction('loss-cover')"
style="font-size:11px;padding:6px 8px;background:#fff;color:#15803d;border:1px solid #86efac;border-radius:6px;cursor:pointer;">🎁 买单活动</button>
@endif
@if (Auth::id() === 1)
<button type="button" onclick="runAdminAction('refresh-all')"
style="font-size:11px;padding:6px 8px;background:#fff;color:#0f766e;border:1px solid #99f6e4;border-radius:6px;cursor:pointer;">♻️ 刷新全员</button>
@endif
</div>
@endif
+125 -2
View File
@@ -672,6 +672,9 @@
case 'loss-cover':
openAdminBaccaratLossCoverModal();
break;
case 'refresh-all':
refreshAllBrowsers();
break;
default:
break;
}
@@ -691,6 +694,57 @@
triggerEffect(type);
}
/**
* 站长通知当前房间所有在线用户刷新页面。
*/
async function refreshAllBrowsers() {
if (!window.chatContext?.isSiteOwner || !window.chatContext?.refreshAllUrl) {
window.chatDialog?.alert('仅站长可执行全员刷新。', '无权限', '#cc4444');
return;
}
const confirmed = await window.chatDialog?.confirm(
'确定通知当前房间所有在线用户刷新页面吗?\n适用于功能更新后强制同步最新按钮与权限状态。',
'♻️ 刷新全员',
'#0f766e'
);
if (!confirmed) {
return;
}
try {
const response = await fetch(window.chatContext.refreshAllUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || '',
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
room_id: window.chatContext.roomId,
reason: '功能更新,站长要求刷新页面',
}),
});
const data = await response.json();
if (data.status === 'success') {
window.chatToast?.show({
title: '已发送刷新通知',
message: data.message,
icon: '♻️',
color: '#0f766e',
duration: 3500,
});
return;
}
window.chatDialog?.alert(data.message || '发送刷新通知失败', '操作失败', '#cc4444');
} catch (error) {
window.chatDialog?.alert('网络异常,请稍后再试', '错误', '#cc4444');
}
}
/**
* 将选中的欢迎语模板填入输入框,{name} 替换为当前选中的聊天对象,
* 并在前面加上「部门 职务 姓名:」前缀,然后自动发送
@@ -1436,6 +1490,48 @@
document.getElementById('room-title-display').innerText = e.detail.title;
});
/**
* 收到站长的全员刷新通知后,先弹出提示,再延迟刷新页面。
*/
window.addEventListener('chat:browser-refresh-requested', (e) => {
const detail = e.detail || {};
const operatorName = escapeHtml(String(detail.operator || '站长'));
const reasonText = escapeHtml(String(detail.reason || '页面功能已更新,请重新载入。'));
window.chatToast?.show({
title: '页面即将刷新',
message: `<b>${operatorName}</b> 通知全员刷新页面。<br><span style="color:#475569;">${reasonText}</span>`,
icon: '♻️',
color: '#0f766e',
duration: 2200,
});
window.setTimeout(() => {
window.location.reload();
}, 900);
});
/**
* 任命/撤职后,目标用户收到定向刷新通知,自动同步页面上的权限按钮。
*/
window.addEventListener('chat:user-browser-refresh-requested', (e) => {
const detail = e.detail || {};
const operatorName = escapeHtml(String(detail.operator || '管理员'));
const reasonText = escapeHtml(String(detail.reason || '你的权限状态已发生变化,页面即将刷新。'));
window.chatToast?.show({
title: '权限同步中',
message: `<b>${operatorName}</b> 已更新你的职务状态。<br><span style="color:#475569;">${reasonText}</span>`,
icon: '🔄',
color: '#7c3aed',
duration: 2600,
});
window.setTimeout(() => {
window.location.reload();
}, 1000);
});
// ── 管理员全员清屏事件(等待 Echo 就绪后监听) ───────
function setupScreenClearedListener() {
if (!window.Echo || !window.chatContext) {
@@ -1484,6 +1580,32 @@
// DOMContentLoaded 后启动,确保 Vite 编译的 JS 已加载
document.addEventListener('DOMContentLoaded', setupScreenClearedListener);
/**
* 注册房间级“刷新全员”监听。
*
* 放在 Blade 脚本内,避免前端资源未重新构建时收不到刷新广播。
*/
function setupRoomBrowserRefreshListener() {
if (!window.Echo || !window.chatContext) {
setTimeout(setupRoomBrowserRefreshListener, 500);
return;
}
window.Echo.join(`room.${window.chatContext.roomId}`)
.listen('BrowserRefreshRequested', (e) => {
console.log('收到全员刷新事件:', e);
window.dispatchEvent(
new CustomEvent('chat:browser-refresh-requested', {
detail: e
})
);
});
console.log('BrowserRefreshRequested 监听器已注册');
}
document.addEventListener('DOMContentLoaded', setupRoomBrowserRefreshListener);
// ── 开发日志发布通知(仅 Room 1 大厅可见)────────────
/**
* 监听 ChangelogPublished 事件,在大厅聊天区展示系统通知
@@ -1642,11 +1764,12 @@
window.addEventListener('chat:effect', (e) => {
const type = e.detail?.type;
const target = e.detail?.target_username; // null = 全员,otherwise 指定昵称
const operator = e.detail?.operator; // 定向赠送时,购买者自己也应能看到特效
const myName = window.chatContext?.username;
// null 表示全员,或者 target 匹配自己才播放
// null 表示全员;若有指定接收者,则购买者本人和指定用户都播放
if (type && typeof EffectManager !== 'undefined') {
if (!target || target === myName) {
if (!target || target === myName || operator === myName) {
EffectManager.play(type);
}
}
@@ -349,13 +349,10 @@
});
const data = await res.json();
const revOk = data.status === 'success';
this.$alert(
data.message,
revOk ? '撤销成功' : '操作失败',
revOk ? '#6b7280' : '#cc4444'
);
if (revOk) {
this.showUserModal = false;
} else {
this.$alert(data.message, '操作失败', '#cc4444');
}
} catch (e) {
this.$alert('网络异常', '错误', '#cc4444');