diff --git a/resources/js/chat-room.js b/resources/js/chat-room.js index e3786d5..b85f5b5 100644 --- a/resources/js/chat-room.js +++ b/resources/js/chat-room.js @@ -766,12 +766,12 @@ if (typeof window !== "undefined") { bindHorseRaceFabControls(); bindHorseRaceEvents(); bindHolidayModalControls(); + bindMarriageModalControls(); bindChatInitialStateControls(); bindBankControls(); bindFishingControls(); bindFortunePanelControls(); bindMarriageStatusControls(); - bindMarriageModalControls(); bindProfileControls(); bindShopControls(); bindCompactShopPanelControls(); diff --git a/resources/js/chat-room/marriage-modals.js b/resources/js/chat-room/marriage-modals.js index d49aaf7..7660cbc 100644 --- a/resources/js/chat-room/marriage-modals.js +++ b/resources/js/chat-room/marriage-modals.js @@ -80,6 +80,199 @@ export function openWeddingSetupModal(marriageId) { } } +/** + * 读取 Alpine 组件数据,避免直接访问 Alpine 私有字段。 + * + * @param {string} modalId 弹窗节点 ID + * @returns {Record|null} + */ +function getAlpineModalData(modalId) { + const modal = document.getElementById(modalId); + const alpine = window.Alpine; + + if (!modal || !alpine) { + return null; + } + + return alpine.$data(modal); +} + +/** + * 构建婚礼红包领取按钮 HTML,按钮通过 ceremonyId 读取全局缓存。 + * + * @param {number|string} ceremonyId 婚礼场次 ID + * @returns {string} + */ +function buildWeddingClaimButton(ceremonyId) { + return ``; +} + +/** + * 将红包详情写入全局缓存,供领取按钮和状态面板复用。 + * + * @param {number|string} ceremonyId 婚礼场次 ID + * @param {Record} detail 红包详情 + * @returns {void} + */ +function cacheWeddingEnvelope(ceremonyId, detail) { + if (!window._weddingEnvelopes) { + window._weddingEnvelopes = {}; + } + + window._weddingEnvelopes[ceremonyId] = detail; +} + +/** + * 绑定婚姻系统广播事件,处理弹窗、公告和红包到账提示。 + * + * @returns {void} + */ +function bindMarriageModalEvents() { + if (window.__marriageModalEventsBound) { + return; + } + + window.__marriageModalEventsBound = true; + + window.addEventListener("chat:marriage-accepted", (event) => { + const detail = event.detail; + const groomName = detail.user?.username ?? detail.groom_name ?? "??"; + const brideName = detail.partner?.username ?? detail.bride_name ?? "??"; + + if (typeof window.appendSystemMessage === "function") { + window.appendSystemMessage(`💑 ${groomName} 与 ${brideName} 喜结连理!`); + } + + getAlpineModalData("marriage-accepted-modal")?.open(detail); + }); + + window.addEventListener("chat:marriage-proposed", (event) => { + getAlpineModalData("marriage-incoming-modal")?.open(event.detail); + }); + + window.addEventListener("chat:wedding-celebration", (event) => { + const detail = event.detail; + const groomName = detail.user?.username ?? "??"; + const brideName = detail.partner?.username ?? "??"; + const tierIcon = detail.tier_icon ?? "🎊"; + const tierName = detail.tier_name ?? "婚礼"; + const amount = detail.total_amount ? Number(detail.total_amount).toLocaleString() : "?"; + const ceremonyId = detail.ceremony_id; + + cacheWeddingEnvelope(ceremonyId, detail); + + if (typeof window.appendSystemMessage === "function") { + window.appendSystemMessage( + `${tierIcon} ${groomName} 与 ${brideName} 举办了【${tierName}】!总金额 💰${amount} 金币,快来抢红包!${buildWeddingClaimButton(ceremonyId)}`, + ); + } + + getAlpineModalData("wedding-envelope-modal")?.open(detail); + }); + + window.addEventListener("chat:marriage-rejected", (event) => { + const { partner_name: partnerName } = event.detail; + window.chatDialog?.alert(`${partnerName} 婉拒了你的求婚,戒指随之遗失… 💔`, "求婚被拒绝", "#6b7280"); + }); + + window.addEventListener("chat:marriage-expired", () => { + window.chatDialog?.alert("你的求婚超时未获回应,戒指已消失… ⏰", "求婚已过期", "#9ca3af"); + }); + + window.addEventListener("chat:divorce-requested", (event) => { + getAlpineModalData("divorce-request-modal")?.open(event.detail); + }); + + window.addEventListener("chat:envelope-claimed", (event) => { + const { amount } = event.detail; + window.chatDialog?.alert(`+${amount.toLocaleString()} 金币已到账 🎉`, "红包到手!", "#f59e0b"); + }); + + window.addEventListener("chat:marriage-divorced", (event) => { + const detail = event.detail; + const userName = detail.user_username ?? detail.user?.username ?? "??"; + const partnerName = detail.partner_username ?? detail.partner?.username ?? "??"; + + if (typeof window.appendSystemMessage === "function") { + window.appendSystemMessage(`💔 ${userName} 与 ${partnerName} 解除了婚姻关系。`); + } + + getAlpineModalData("marriage-divorced-modal")?.open(detail); + }); +} + +/** + * 页面恢复时查询未领取婚礼红包,并补回公屏领取入口。 + * + * @returns {void} + */ +function restorePendingWeddingEnvelopes() { + const deferBootstrap = window.deferChatGameBootstrap || ((callback, delay = 0) => setTimeout(callback, delay)); + + deferBootstrap(async () => { + try { + const response = await fetch("/wedding/pending-envelopes", { + headers: { + Accept: "application/json", + }, + }); + const data = await response.json(); + + if (!response.ok || !data.envelopes?.length) { + return; + } + + data.envelopes.forEach((envelope) => { + const ceremonyId = envelope.ceremony_id; + + cacheWeddingEnvelope(ceremonyId, { + ceremony_id: ceremonyId, + total_amount: envelope.total_amount, + tier_name: envelope.tier_name, + tier_icon: envelope.tier_icon, + user: { + username: envelope.groom, + }, + partner: { + username: envelope.bride, + }, + }); + + if (typeof window.appendSystemMessage === "function") { + window.appendSystemMessage( + `⚠️ 您有来自 ${envelope.tier_icon} ${envelope.groom} 与 ${envelope.bride}【${envelope.tier_name}】的婚礼红包未领取!${buildWeddingClaimButton(ceremonyId)}`, + ); + } + }); + } catch (error) { + console.warn("[婚礼红包] 恢复待领取按钮失败", error); + } + }, 3000); +} + +/** + * 页面就绪后初始化婚姻私人频道和待领取红包恢复。 + * + * @returns {void} + */ +function bindMarriageModalBootstrap() { + document.addEventListener("DOMContentLoaded", () => { + const userId = window.chatContext?.userId; + + if (userId && typeof window.initMarriagePrivateChannel === "function") { + // Echo 初始化可能晚于 DOM 就绪,保留短延迟避免私人频道注册失败。 + setTimeout(() => window.initMarriagePrivateChannel(userId), 1500); + } + + restorePendingWeddingEnvelopes(); + }); +} + /** * 暴露婚姻弹窗存量入口,兼容 Blade 内 onclick、Alpine 方法和广播回调。 * @@ -89,4 +282,7 @@ export function bindMarriageModalControls() { window.appendSystemMessage = appendSystemMessage; window.openProposeModal = openProposeModal; window.openWeddingSetupModal = openWeddingSetupModal; + + bindMarriageModalEvents(); + bindMarriageModalBootstrap(); } diff --git a/resources/views/chat/partials/marriage-modals.blade.php b/resources/views/chat/partials/marriage-modals.blade.php index debe7a2..f2d7e54 100644 --- a/resources/views/chat/partials/marriage-modals.blade.php +++ b/resources/views/chat/partials/marriage-modals.blade.php @@ -1232,175 +1232,4 @@ } }; } - - // ───────── WebSocket 事件处理 ─────────────────────────── - - /** 收到全局结婚公告:弹出全屏通知 + 追加公屏文字 */ - window.addEventListener('chat:marriage-accepted', (e) => { - const detail = e.detail; - const groomName = detail.user?.username ?? detail.groom_name ?? '??'; - const brideName = detail.partner?.username ?? detail.bride_name ?? '??'; - // 追加公屏消息 - if (typeof window.appendSystemMessage === 'function') { - window.appendSystemMessage(`💑 ${groomName} 与 ${brideName} 喜结连理!`); - } - // 弹出全屏公告(fireworks 效果) - const el = document.getElementById('marriage-accepted-modal'); - if (el) Alpine.$data(el).open(detail); - }); - - - /** 收到求婚通知(私人频道,目标方) */ - window.addEventListener('chat:marriage-proposed', (e) => { - const detail = e.detail; - const el = document.getElementById('marriage-incoming-modal'); - if (el) Alpine.$data(el).open(detail); - }); - - /** 收到婚礼庆典(全局,显示红包 + 公屏系统消息) */ - window.addEventListener('chat:wedding-celebration', (e) => { - const detail = e.detail; - const groomName = detail.user?.username ?? '??'; - const brideName = detail.partner?.username ?? '??'; - const tierIcon = detail.tier_icon ?? '🎊'; - const tierName = detail.tier_name ?? '婚礼'; - const amount = detail.total_amount ? Number(detail.total_amount).toLocaleString() : '?'; - const ceremonyId = detail.ceremony_id; - - // 将 detail 存入全局 Map,避免 onclick 属性内嵌 JSON 被双引号破坏 - if (!window._weddingEnvelopes) window._weddingEnvelopes = {}; - window._weddingEnvelopes[ceremonyId] = detail; - - // 公屏追加带按钮的系统消息(按钮通过 ceremonyId 引用全局 Map) - if (typeof window.appendSystemMessage === 'function') { - const claimBtn = ``; - window.appendSystemMessage( - `${tierIcon} ${groomName} 与 ${brideName} 举办了【${tierName}】!总金额 💰${amount} 金币,快来抢红包!${claimBtn}` - ); - } - - // 同时弹出全屏红包弹窗 - const el = document.getElementById('wedding-envelope-modal'); - if (el) Alpine.$data(el).open(detail); - - }); - - - /** 求婚被拒(私人频道,发起方) */ - window.addEventListener('chat:marriage-rejected', (e) => { - const { - proposer_name, - partner_name - } = e.detail; - window.chatDialog?.alert( - `${partner_name} 婉拒了你的求婚,戒指随之遗失… 💔`, - '求婚被拒绝', - '#6b7280' - ); - }); - - /** 求婚超时(私人频道,发起方) */ - window.addEventListener('chat:marriage-expired', (e) => { - window.chatDialog?.alert( - '你的求婚超时未获回应,戒指已消失… ⏰', - '求婚已过期', - '#9ca3af' - ); - }); - - /** 接到协议离婚申请(私人频道,对方)→ 打开专属三选弹窗 */ - window.addEventListener('chat:divorce-requested', (e) => { - const detail = e.detail; - const el = document.getElementById('divorce-request-modal'); - if (el) Alpine.$data(el).open(detail); - }); - - - - /** 红包领取成功通知(私人频道) */ - window.addEventListener('chat:envelope-claimed', (e) => { - const { - amount - } = e.detail; - window.chatDialog?.alert(`+${amount.toLocaleString()} 金币已到账 🎉`, '红包到手!', '#f59e0b'); - }); - - - window.addEventListener('chat:marriage-divorced', (e) => { - const detail = e.detail; - const userName = detail.user_username ?? detail.user?.username ?? '??'; - const partnerName = detail.partner_username ?? detail.partner?.username ?? '??'; - // 追加公屏文字 - if (typeof window.appendSystemMessage === 'function') { - window.appendSystemMessage(`💔 ${userName} 与 ${partnerName} 解除了婚姻关系。`); - } - // 触发全屏离婚公告弹窗(暗色阴郁风格 + 雷雨特效) - const modal = document.getElementById('marriage-divorced-modal')?._x_dataStack?.[0]; - if (modal && typeof modal.open === 'function') modal.open(detail); - }); - - - /** 页面加载完成后初始化私人频道监听 */ - document.addEventListener('DOMContentLoaded', () => { - const userId = window.chatContext?.userId; - if (userId && typeof window.initMarriagePrivateChannel === 'function') { - // 延迟初始化,确保 Echo 已就绪 - setTimeout(() => window.initMarriagePrivateChannel(userId), 1500); - } - - // ── 页面刷新后恢复婚礼红包领取按钮 ───────────────────────── - // 空闲时再查待领取红包,避免和聊天室首屏消息/名单初始化抢网络。 - window.deferChatGameBootstrap(async () => { - try { - const res = await fetch('/wedding/pending-envelopes', { - headers: { - 'Accept': 'application/json' - } - }); - const data = await res.json(); - if (!res.ok || !data.envelopes?.length) return; - - // 初始化全局缓存 - if (!window._weddingEnvelopes) window._weddingEnvelopes = {}; - - data.envelopes.forEach(env => { - const ceremonyId = env.ceremony_id; - - // 注入 detail 到全局 Map,供领取弹窗使用 - window._weddingEnvelopes[ceremonyId] = { - ceremony_id: ceremonyId, - total_amount: env.total_amount, - tier_name: env.tier_name, - tier_icon: env.tier_icon, - user: { - username: env.groom - }, - partner: { - username: env.bride - }, - }; - - // 在包厢窗口追加提示 + 领取按钮 - if (typeof window.appendSystemMessage === 'function') { - const claimBtn = ``; - window.appendSystemMessage( - `⚠️ 您有来自 ${env.tier_icon} ${env.groom} 与 ${env.bride}【${env.tier_name}】的婚礼红包未领取!${claimBtn}` - ); - } - }); - } catch (e) { - console.warn('[婚礼红包] 恢复待领取按钮失败', e); - } - }, 3000); - });