// 婚姻弹窗辅助入口,承接从 marriage-modals.blade.php 迁移出的全局函数。 /** * 向聊天主窗口追加一条婚姻系统公告,允许传入受控 HTML 按钮。 * * @param {string} html 系统模板生成的 HTML 内容 * @returns {void} */ export function appendSystemMessage(html) { const container = document.getElementById("chat-messages-container"); if (!container) { return; } const div = document.createElement("div"); div.style.cssText = "background:linear-gradient(135deg,#fdf4ff,#fce7f3); border-left:3px solid #ec4899; border-radius:6px; padding:5px 12px; margin:3px 0; font-size:13px; line-height:1.6;"; div.innerHTML = `${html}`; container.appendChild(div); container.scrollTop = container.scrollHeight; } /** * 打开求婚弹窗入口,从用户名片按钮触发。 * * @param {string} username 求婚对象用户名 * @returns {Promise} */ export async function openProposeModal(username) { let rings = []; try { const response = await fetch(window.chatContext.marriage.myRingsUrl, { headers: { Accept: "application/json", }, }); const data = await response.json(); if (data.status === "success") { rings = data.rings || []; } } catch { // 网络异常时继续交给后端兜底,避免前端误拦截真实可用的求婚流程。 } if (rings.length === 0) { const goShop = await window.chatDialog?.confirm( "求婚需要一枚💍结婚戒指,你的背包里还没有。\n\n要前往商店购买吗?", "需要结婚戒指", ); if (goShop && typeof window.openShopModal === "function") { window.openShopModal(); } return; } const modal = document.getElementById("marriage-propose-modal"); const alpine = window.Alpine; if (modal && alpine) { alpine.$data(modal).openWithRings(username, rings); } } /** * 打开婚礼设置弹窗,供新婚公告和名片入口复用。 * * @param {number|string} marriageId 婚姻记录 ID * @returns {void} */ export function openWeddingSetupModal(marriageId) { const modal = document.getElementById("wedding-setup-modal"); const alpine = window.Alpine; if (modal && alpine) { alpine.$data(modal).open(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 方法和广播回调。 * * @returns {void} */ export function bindMarriageModalControls() { window.appendSystemMessage = appendSystemMessage; window.openProposeModal = openProposeModal; window.openWeddingSetupModal = openWeddingSetupModal; bindMarriageModalEvents(); bindMarriageModalBootstrap(); }