From b9c703b755c17d555caad72037871d2f06bb20dc Mon Sep 17 00:00:00 2001 From: lkddi Date: Thu, 12 Mar 2026 07:33:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9A=E5=B0=86=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E5=AE=A4=E6=89=80=E6=9C=89=E5=8E=9F=E7=94=9F=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E6=9B=BF=E6=8D=A2=E4=B8=BA=E5=85=A8=E5=B1=80=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=EF=BC=8C=E5=85=AC=E5=91=8A=E5=A2=9E=E5=8A=A0=E5=8F=91?= =?UTF-8?q?=E9=80=81=E8=80=85=E4=B8=8E=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将设公告、公屏讲话、全员清屏按钮弹窗改为使用 window.chatDialog 全局弹窗 - 所有弹窗改用 .then() 回调注册事件,避免 async/await 行为不一致问题 - 公告内容末尾追加「——发送者 MM-dd HH:mm」,无需新增数据库字段 - 前端编辑公告时自动剥离末尾元信息,用户仅编辑纯内容 - 修复 red-packet-panel.blade.php 中 3 处原生 alert() 残留 - 修复 shop-panel.blade.php 中购买确认 confirm() 原生弹窗残留 --- app/Http/Controllers/ChatController.php | 4 +- .../partials/games/red-packet-panel.blade.php | 16 ++-- .../views/chat/partials/scripts.blade.php | 85 ++++++++++--------- .../views/chat/partials/shop-panel.blade.php | 67 ++++++++------- 4 files changed, 93 insertions(+), 79 deletions(-) diff --git a/app/Http/Controllers/ChatController.php b/app/Http/Controllers/ChatController.php index 49bd074..9f6a965 100644 --- a/app/Http/Controllers/ChatController.php +++ b/app/Http/Controllers/ChatController.php @@ -731,7 +731,9 @@ class ChatController extends Controller 'announcement' => 'required|string|max:500', ]); - $room->announcement = $request->input('announcement'); + // 将发送者和发送时间追加到公告文本末尾,持久化存储,无需额外字段 + $room->announcement = trim($request->input('announcement')) + .' ——'.$user->username.' '.now()->format('m-d H:i'); $room->save(); // 广播公告更新到所有在线用户 diff --git a/resources/views/chat/partials/games/red-packet-panel.blade.php b/resources/views/chat/partials/games/red-packet-panel.blade.php index 2e07c3c..9a24ee7 100644 --- a/resources/views/chat/partials/games/red-packet-panel.blade.php +++ b/resources/views/chat/partials/games/red-packet-panel.blade.php @@ -416,11 +416,13 @@ // 【前置拦截1】如果有时间戳并算出已过期,直接杀死不弹窗 if (sentAtUnix && Date.now() >= calculatedExpireAt) { - if (typeof window.chatToast === 'function') { - window.chatToast('该红包已过期。', 'info'); - } else { - alert('该红包已过期。'); - } + window.chatToast?.show({ + title: '⏰ 礼包已过期', + message: '该红包已过期,无法领取。', + icon: '⏰', + color: '#9ca3af', + duration: 4000, + }); console.log('红包已准确断定过期,拦截弹窗显示:', envelopeId); return; } @@ -499,7 +501,7 @@ const modalEl = document.getElementById('red-packet-modal'); if (!modalEl) { - alert('致命错误:红包视图容器 #red-packet-modal 找不到!'); + window.chatDialog?.alert('致命错误:红包视图容器 #red-packet-modal 找不到!', '系统错误', '#cc4444'); return; } @@ -543,7 +545,7 @@ } } catch (err) { console.error('showRedPacketModal 执行失败:', err); - alert('红包弹窗初始化异常: ' + err.message); + window.chatDialog?.alert('红包弹窗初始化异常: ' + err.message, '系统错误', '#cc4444'); } // 启动倒计时 diff --git a/resources/views/chat/partials/scripts.blade.php b/resources/views/chat/partials/scripts.blade.php index 4c1e090..cb0dc63 100644 --- a/resources/views/chat/partials/scripts.blade.php +++ b/resources/views/chat/partials/scripts.blade.php @@ -986,13 +986,15 @@ // ── 设置房间公告 ───────────────────────────────────── - async function promptAnnouncement() { - const currentText = document.getElementById('announcement-text')?.textContent?.trim() || ''; - const newText = prompt('请输入新的房间公告/祝福语:', currentText); - if (newText === null || newText.trim() === '') return; + function promptAnnouncement() { + // 从 marquee 读取当前公告全文,剥离末尾的「——发送者 日期」元信息,仅预填纯内容 + const fullText = document.getElementById('announcement-text')?.textContent?.trim() || ''; + const pureText = fullText.replace(/ ——\S+ \d{2}-\d{2} \d{2}:\d{2}$/, '').trim(); + // 使用全局弹窗替代原生 prompt(),通过 .then() 注册回调确保事件正确触发 + window.chatDialog.prompt('请输入新的房间公告/祝福语:', pureText, '设置公告', '#336699').then(newText => { + if (newText === null || newText.trim() === '') return; - try { - const res = await fetch(`/room/${window.chatContext.roomId}/announcement`, { + fetch(`/room/${window.chatContext.roomId}/announcement`, { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute( @@ -1003,27 +1005,28 @@ body: JSON.stringify({ announcement: newText.trim() }) + }).then(res => res.json()).then(data => { + if (data.status === 'success') { + // 用后端返回的含发送者+时间的完整公告文本更新滚动条 + const marquee = document.getElementById('announcement-text'); + if (marquee) marquee.textContent = data.announcement; + window.chatDialog.alert('公告已更新!', '提示', '#16a34a'); + } else { + window.chatDialog.alert(data.message || '更新失败', '操作失败', '#cc4444'); + } + }).catch(e => { + window.chatDialog.alert('设置公告失败:' + e.message, '操作失败', '#cc4444'); }); - const data = await res.json(); - if (data.status === 'success') { - const marquee = document.getElementById('announcement-text'); - if (marquee) marquee.textContent = newText.trim(); - window.chatDialog.alert('公告已更新!', '提示', '#16a34a'); - } else { - window.chatDialog.alert(data.message || '更新失败', '操作失败', '#cc4444'); - } - } catch (e) { - window.chatDialog.alert('设置公告失败:' + e.message, '操作失败', '#cc4444'); - } + }); } // ── 站长公屏讲话 ───────────────────────────────────── - async function promptAnnounceMessage() { - const content = prompt('请输入公屏讲话内容:'); - if (!content || !content.trim()) return; + function promptAnnounceMessage() { + // 使用全局弹窗替代原生 prompt(),通过 .then() 注册回调确保事件正确触发 + window.chatDialog.prompt('请输入公屏讲话内容:', '', '📢 公屏讲话', '#7c3aed').then(content => { + if (!content || !content.trim()) return; - try { - const res = await fetch('/command/announce', { + fetch('/command/announce', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute( @@ -1035,22 +1038,23 @@ content: content.trim(), room_id: window.chatContext.roomId, }) + }).then(res => res.json()).then(data => { + if (data.status !== 'success') { + window.chatDialog.alert(data.message || '发送失败', '操作失败', '#cc4444'); + } + }).catch(e => { + window.chatDialog.alert('发送失败:' + e.message, '操作失败', '#cc4444'); }); - const data = await res.json(); - if (!res.ok || data.status !== 'success') { - window.chatDialog.alert(data.message || '发送失败', '操作失败', '#cc4444'); - } - } catch (e) { - window.chatDialog.alert('发送失败:' + e.message, '操作失败', '#cc4444'); - } + }); } // ── 管理员全员清屏 ───────────────────────────────────── - async function adminClearScreen() { - if (!confirm('确定要清除所有人的聊天记录吗?(悄悄话将保留)')) return; + function adminClearScreen() { + // 使用全局弹窗替代原生 confirm(),通过 .then() 注册回调确保事件正确触发 + window.chatDialog.confirm('确定要清除所有人的聊天记录吗?(悄悄话将保留)', '全员清屏', '#dc2626').then(ok => { + if (!ok) return; - try { - const res = await fetch('/command/clear-screen', { + fetch('/command/clear-screen', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute( @@ -1061,14 +1065,14 @@ body: JSON.stringify({ room_id: window.chatContext.roomId, }) + }).then(res => res.json()).then(data => { + if (data.status !== 'success') { + window.chatDialog.alert(data.message || '清屏失败', '操作失败', '#cc4444'); + } + }).catch(e => { + window.chatDialog.alert('清屏失败:' + e.message, '操作失败', '#cc4444'); }); - const data = await res.json(); - if (!res.ok || data.status !== 'success') { - window.chatDialog.alert(data.message || '清屏失败', '操作失败', '#cc4444'); - } - } catch (e) { - window.chatDialog.alert('清屏失败:' + e.message, '操作失败', '#cc4444'); - } + }); } // ── 本地清屏(仅限自己的屏幕)─────────────────────────── @@ -1273,5 +1277,4 @@ div.textContent = text; return div.innerHTML; } - diff --git a/resources/views/chat/partials/shop-panel.blade.php b/resources/views/chat/partials/shop-panel.blade.php index 1e380d4..8af592b 100644 --- a/resources/views/chat/partials/shop-panel.blade.php +++ b/resources/views/chat/partials/shop-panel.blade.php @@ -452,36 +452,43 @@ /** 购买商品 */ window.buyItem = function(itemId, name, price) { - if (!confirm(`确定花费 ${Number(price).toLocaleString()} 金币购买【${name}】吗?`)) return; - fetch('{{ route('shop.buy') }}', { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': _csrf() - }, - body: JSON.stringify({ - item_id: itemId - }), - }) - .then(r => r.json()) - .then(data => { - showShopToast(data.message, data.status === 'success'); - if (data.status === 'success') { - if (data.jjb !== undefined) - document.getElementById('shop-jjb').textContent = Number(data.jjb) - .toLocaleString(); - if (data.play_effect && window.EffectManager) - window.EffectManager.play(data.play_effect); - // 刷新商品状态 - shopLoaded = false; - setTimeout(() => { - fetchShopData(); - shopLoaded = true; - }, 800); - } - }) - .catch(() => showShopToast('⚠ 网络异常,请重试', false)); + // 使用全局弹窗替代原生 confirm(),通过 .then() 注册回调确保事件正确触发 + window.chatDialog.confirm( + `确定花费 ${Number(price).toLocaleString()} 金币购买【${name}】吗?`, + '确认购买', + '#336699' + ).then(ok => { + if (!ok) return; + fetch('{{ route('shop.buy') }}', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': _csrf() + }, + body: JSON.stringify({ + item_id: itemId + }), + }) + .then(r => r.json()) + .then(data => { + showShopToast(data.message, data.status === 'success'); + if (data.status === 'success') { + if (data.jjb !== undefined) + document.getElementById('shop-jjb').textContent = Number(data.jjb) + .toLocaleString(); + if (data.play_effect && window.EffectManager) + window.EffectManager.play(data.play_effect); + // 刷新商品状态 + shopLoaded = false; + setTimeout(() => { + fetchShopData(); + shopLoaded = true; + }, 800); + } + }) + .catch(() => showShopToast('⚠ 网络异常,请重试', false)); + }); }; /** Toast 通知 */