Files

399 lines
14 KiB
JavaScript

import "./bootstrap";
// 这个文件负责处理浏览器与 Laravel Reverb WebSocket 服务器的通信。
// 通过 Presence Channel 实现聊天室的核心监听。
function isHolidayObject(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function firstHolidayDefined(...values) {
for (const value of values) {
if (value !== undefined && value !== null && value !== "") {
return value;
}
}
return null;
}
function pickHolidayObject(...values) {
for (const value of values) {
if (isHolidayObject(value)) {
return value;
}
}
return {};
}
function mergeHolidayObjects(...values) {
return Object.assign({}, ...values.filter(isHolidayObject));
}
function toHolidayNumber(value, fallback = null) {
if (value === undefined || value === null || value === "") {
return fallback;
}
const parsedValue = Number(value);
return Number.isFinite(parsedValue) ? parsedValue : fallback;
}
export function normalizeHolidayBroadcastEvent(payload = {}) {
const runPayload = pickHolidayObject(payload.run, payload.holiday_run);
const snapshotPayload = pickHolidayObject(
payload.snapshot,
payload.run_snapshot,
payload.batch_snapshot,
runPayload.snapshot,
runPayload.batch_snapshot,
);
const eventPayload = pickHolidayObject(
payload.event,
payload.holiday_event,
runPayload.event,
runPayload.template,
snapshotPayload.event,
snapshotPayload.template,
);
const mergedPayload = mergeHolidayObjects(
eventPayload,
payload,
runPayload,
snapshotPayload,
);
const fixedAmount = toHolidayNumber(
firstHolidayDefined(
snapshotPayload.fixed_amount,
runPayload.fixed_amount,
payload.fixed_amount,
),
);
return {
...payload,
...mergedPayload,
run_id: firstHolidayDefined(
payload.run_id,
runPayload.run_id,
runPayload.id,
snapshotPayload.run_id,
),
event_id: firstHolidayDefined(
payload.event_id,
runPayload.event_id,
snapshotPayload.event_id,
eventPayload.id,
),
name: firstHolidayDefined(
snapshotPayload.name,
runPayload.name,
payload.name,
eventPayload.name,
"节日福利",
),
description: firstHolidayDefined(
snapshotPayload.description,
runPayload.description,
payload.description,
eventPayload.description,
"",
),
total_amount:
toHolidayNumber(
firstHolidayDefined(
snapshotPayload.total_amount,
runPayload.total_amount,
payload.total_amount,
),
0,
) ?? 0,
max_claimants:
toHolidayNumber(
firstHolidayDefined(
snapshotPayload.max_claimants,
runPayload.max_claimants,
payload.max_claimants,
),
0,
) ?? 0,
distribute_type: firstHolidayDefined(
snapshotPayload.distribute_type,
runPayload.distribute_type,
payload.distribute_type,
fixedAmount !== null ? "fixed" : "random",
),
fixed_amount: fixedAmount,
scheduled_for: firstHolidayDefined(
snapshotPayload.scheduled_for,
runPayload.scheduled_for,
payload.scheduled_for,
snapshotPayload.send_at,
runPayload.send_at,
payload.send_at,
),
expires_at: firstHolidayDefined(
snapshotPayload.expires_at,
runPayload.expires_at,
payload.expires_at,
snapshotPayload.claim_deadline_at,
runPayload.claim_deadline_at,
payload.claim_deadline_at,
),
repeat_type: firstHolidayDefined(
snapshotPayload.repeat_type,
runPayload.repeat_type,
payload.repeat_type,
eventPayload.repeat_type,
),
round_no: firstHolidayDefined(
snapshotPayload.round_no,
runPayload.round_no,
payload.round_no,
snapshotPayload.sequence,
runPayload.sequence,
payload.sequence,
snapshotPayload.issue_no,
runPayload.issue_no,
payload.issue_no,
),
round_label: firstHolidayDefined(
snapshotPayload.round_label,
runPayload.round_label,
payload.round_label,
snapshotPayload.batch_label,
runPayload.batch_label,
payload.batch_label,
),
snapshot: mergeHolidayObjects(eventPayload, runPayload, snapshotPayload),
};
}
window.normalizeHolidayBroadcastEvent = normalizeHolidayBroadcastEvent;
export function initChat(roomId) {
if (!roomId) {
console.error("未提供 roomId,无法初始化 WebSocket 连接。");
return;
}
const userId = window.chatContext?.userId;
// 监听全局系统事件(如 AI 机器人开关)
window.Echo.channel('chat.system')
.listen('ChatBotToggled', (e) => {
console.log("机器人开关:", e);
window.dispatchEvent(new CustomEvent("chat:bot-toggled", { detail: e }));
});
// 加入带有登录人员追踪的 Presence Channel
window.Echo.join(`room.${roomId}`)
// 当自己成功连接时,获取当前在这里的所有人列表
.here((users) => {
console.log("当前房间内的在线人员:", users);
// 触发自定义事件,让具体的前端 UI 去接管渲染
window.dispatchEvent(
new CustomEvent("chat:here", { detail: users }),
);
})
// 监听其他人的加入
.joining((user) => {
console.log(user.username + " 进入了房间");
window.dispatchEvent(
new CustomEvent("chat:joining", { detail: user }),
);
})
// 监听其他人的离开
.leaving((user) => {
console.log(user.username + " 离开了房间");
window.dispatchEvent(
new CustomEvent("chat:leaving", { detail: user }),
);
})
// 监听新发送的文本消息
.listen("MessageSent", (e) => {
console.log("收到新发言:", e.message);
window.dispatchEvent(
new CustomEvent("chat:message", { detail: e.message }),
);
})
// 监听踢出事件(通常判断是不是自己被踢出了)
.listen("UserKicked", (e) => {
console.log("踢出通知:", e);
window.dispatchEvent(new CustomEvent("chat:kicked", { detail: e }));
})
// 监听封口禁言事件
.listen("UserMuted", (e) => {
console.log("禁言通知:", e);
window.dispatchEvent(new CustomEvent("chat:muted", { detail: e }));
})
// 监听房间主题被改变
.listen("RoomTitleUpdated", (e) => {
console.log("主题改变:", e);
window.dispatchEvent(
new CustomEvent("chat:title-updated", { detail: e }),
);
})
// 监听管理员全员清屏
.listen("ScreenCleared", (e) => {
console.log("全员清屏:", e);
window.dispatchEvent(
new CustomEvent("chat:screen-cleared", { detail: e }),
);
})
// 监听站长触发的全员刷新
.listen("BrowserRefreshRequested", (e) => {
console.log("全员刷新:", e);
window.dispatchEvent(
new CustomEvent("chat:browser-refresh-requested", { detail: e }),
);
})
// 监听管理员触发的全屏特效(烟花/下雨/雷电)
.listen("EffectBroadcast", (e) => {
console.log("特效播放:", e);
window.dispatchEvent(new CustomEvent("chat:effect", { detail: e }));
})
// 监听任命公告(礼花 + 隆重弹窗)
.listen("AppointmentAnnounced", (e) => {
console.log("任命公告:", e);
window.dispatchEvent(
new CustomEvent("chat:appointment-announced", { detail: e }),
);
})
// ─── 婚姻系统:全局事件(广播给整个房间) ────────────────
.listen(".marriage.accepted", (e) => {
console.log("结婚公告:", e);
window.dispatchEvent(
new CustomEvent("chat:marriage-accepted", { detail: e }),
);
})
.listen(".marriage.divorced", (e) => {
console.log("离婚公告:", e);
window.dispatchEvent(
new CustomEvent("chat:marriage-divorced", { detail: e }),
);
})
.listen(".wedding.celebration", (e) => {
console.log("婚礼庆典:", e);
window.dispatchEvent(
new CustomEvent("chat:wedding-celebration", { detail: e }),
);
})
// ─── 节日福利:系统定时发放 ────────────────────────────────
.listen(".holiday.started", (e) => {
const holidayPayload = normalizeHolidayBroadcastEvent(e);
console.log("节日福利批次开始:", holidayPayload);
window.dispatchEvent(
new CustomEvent("chat:holiday.started", { detail: holidayPayload }),
);
})
// ─── 百家乐:开局 & 结算 ──────────────────────────────────
.listen(".baccarat.opened", (e) => {
console.log("百家乐开局:", e);
window.dispatchEvent(
new CustomEvent("chat:baccarat.opened", { detail: e }),
);
})
.listen(".baccarat.pool_updated", (e) => {
console.log("百家乐押注更新:", e);
window.dispatchEvent(
new CustomEvent("chat:baccarat.pool_updated", { detail: e }),
);
})
.listen(".baccarat.settled", (e) => {
console.log("百家乐结算:", e);
window.dispatchEvent(
new CustomEvent("chat:baccarat.settled", { detail: e }),
);
})
// ─── 赛马:开场 / 进度 / 结算 ────────────────────────────────
.listen(".horse.opened", (e) => {
console.log("赛马开场:", e);
window.dispatchEvent(
new CustomEvent("chat:horse.opened", { detail: e }),
);
})
.listen(".horse.progress", (e) => {
console.log("赛马进度:", e);
window.dispatchEvent(
new CustomEvent("chat:horse.progress", { detail: e }),
);
})
.listen(".horse.settled", (e) => {
console.log("赛马结算:", e);
window.dispatchEvent(
new CustomEvent("chat:horse.settled", { detail: e }),
);
});
// 监听当前用户私有消息,确保悄悄话与定向系统通知不会泄漏给整个房间。
if (userId) {
window.Echo.private(`user.${userId}`)
.listen("MessageSent", (e) => {
console.log("收到私有聊天消息:", e.message);
window.dispatchEvent(
new CustomEvent("chat:message", { detail: e.message }),
);
})
.listen("UserBrowserRefreshRequested", (e) => {
console.log("收到定向刷新通知:", e);
window.dispatchEvent(
new CustomEvent("chat:user-browser-refresh-requested", { detail: e }),
);
});
}
}
/**
* 初始化婚姻私人频道监听(求婚通知 / 拒绝通知 / 红包领取通知)
* 在用户登录成功后调用,监听 user.{id} 私人频道的婚姻事件。
*
* @param {number} userId 当前登录用户 ID
*/
export function initMarriagePrivateChannel(userId) {
if (!userId || !window.Echo) return;
window.Echo.private(`user.${userId}`)
// 收到求婚通知(目标方)
.listen(".marriage.proposed", (e) => {
console.log("收到求婚:", e);
window.dispatchEvent(
new CustomEvent("chat:marriage-proposed", { detail: e }),
);
})
// 求婚被拒绝(发起方)
.listen(".marriage.rejected", (e) => {
console.log("求婚被拒:", e);
window.dispatchEvent(
new CustomEvent("chat:marriage-rejected", { detail: e }),
);
})
// 求婚过期(发起方)
.listen(".marriage.expired", (e) => {
console.log("求婚超时:", e);
window.dispatchEvent(
new CustomEvent("chat:marriage-expired", { detail: e }),
);
})
// 协议离婚申请通知(对方)
.listen(".marriage.divorce-requested", (e) => {
console.log("离婚申请:", e);
window.dispatchEvent(
new CustomEvent("chat:divorce-requested", { detail: e }),
);
})
// 红包领取成功通知
.listen(".envelope.claimed", (e) => {
console.log("红包到账:", e);
window.dispatchEvent(
new CustomEvent("chat:envelope-claimed", { detail: e }),
);
});
}
// 供全局调用
window.initChat = initChat;
window.initMarriagePrivateChannel = initMarriagePrivateChannel;