224 lines
8.5 KiB
JavaScript
224 lines
8.5 KiB
JavaScript
|
|
// 聊天室共享运行时状态,桥接 Blade 闭包作用域与 Vite 模块。
|
|||
|
|
// 所有需要跨模块共享的可变状态集中在此管理,通过 window.chatState 访问。
|
|||
|
|
|
|||
|
|
export const BLOCKABLE_SYSTEM_SENDERS = ["钓鱼播报", "星海小博士", "百家乐", "跑马", "神秘箱子"];
|
|||
|
|
export const BLOCKED_SYSTEM_SENDERS_STORAGE_KEY = "chat_blocked_system_senders";
|
|||
|
|
export const CHAT_SOUND_MUTED_STORAGE_KEY = "chat_sound_muted";
|
|||
|
|
export const PUBLIC_MESSAGE_NODE_LIMIT = 600;
|
|||
|
|
export const PRIVATE_MESSAGE_NODE_LIMIT = 300;
|
|||
|
|
export const CHAT_MESSAGE_FLUSH_BATCH_SIZE = 8;
|
|||
|
|
export const ROOMS_ONLINE_STATUS_CACHE_TTL = 10000;
|
|||
|
|
export const HEARTBEAT_INTERVAL = 60 * 1000;
|
|||
|
|
export const SYSTEM_USERS = ["钓鱼播报", "星海小博士", "系统传音", "系统公告", "送花播报", "系统", "欢迎", "系统播报", "神秘箱子"];
|
|||
|
|
|
|||
|
|
// 消息动作文字映射表:情绪型(着/地,放"对"之前)和动作型(了,替换"对X说")
|
|||
|
|
export const ACTION_TEXT_MAP = {
|
|||
|
|
"微笑": { type: "emotion", word: "微笑着" },
|
|||
|
|
"大笑": { type: "emotion", word: "大笑着" },
|
|||
|
|
"愤怒": { type: "emotion", word: "愤怒地" },
|
|||
|
|
"哭泣": { type: "emotion", word: "哭泣着" },
|
|||
|
|
"害羞": { type: "emotion", word: "害羞地" },
|
|||
|
|
"鄙视": { type: "emotion", word: "鄙视地" },
|
|||
|
|
"得意": { type: "emotion", word: "得意地" },
|
|||
|
|
"疑惑": { type: "emotion", word: "疑惑地" },
|
|||
|
|
"同情": { type: "emotion", word: "同情地" },
|
|||
|
|
"无奈": { type: "emotion", word: "无奈地" },
|
|||
|
|
"拳打": { type: "verb", word: "拳打了" },
|
|||
|
|
"飞吻": { type: "verb", word: "飞吻了" },
|
|||
|
|
"偷看": { type: "verb", word: "偷看了" },
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ── DOM 引用(惰性获取,避免模块加载时 DOM 未就绪)──
|
|||
|
|
function getContainer() { return document.getElementById("chat-messages-container"); }
|
|||
|
|
function getContainer2() { return document.getElementById("chat-messages-container2"); }
|
|||
|
|
function getUserList() { return document.getElementById("online-users-list"); }
|
|||
|
|
function getToUserSelect() { return document.getElementById("to_user"); }
|
|||
|
|
function getOnlineCount() { return document.getElementById("online-count"); }
|
|||
|
|
function getOnlineCountBottom() { return document.getElementById("online-count-bottom"); }
|
|||
|
|
|
|||
|
|
// ── 可变状态 ──
|
|||
|
|
let onlineUsers = {};
|
|||
|
|
let autoScroll = true;
|
|||
|
|
let maxMsgId = 0;
|
|||
|
|
let pendingChatMessages = [];
|
|||
|
|
let chatMessageFlushTimer = null;
|
|||
|
|
let userListRenderTimer = null;
|
|||
|
|
let userFilterRenderTimer = null;
|
|||
|
|
let userBadgeRotationTick = 0;
|
|||
|
|
let lastAutosaveNode = null;
|
|||
|
|
let roomsRefreshTimer = null;
|
|||
|
|
let roomsOnlineStatusCache = null;
|
|||
|
|
let roomsOnlineStatusCacheAt = 0;
|
|||
|
|
let isMutedUntil = 0;
|
|||
|
|
let imeComposing = false;
|
|||
|
|
let isSending = false;
|
|||
|
|
let sendStartedAt = 0;
|
|||
|
|
let leaveRequestInFlight = false;
|
|||
|
|
let heartbeatFailCount = 0;
|
|||
|
|
const MAX_HEARTBEAT_FAILS = 3;
|
|||
|
|
|
|||
|
|
// 偏好状态
|
|||
|
|
let blockedSystemSenders = new Set();
|
|||
|
|
let initialChatPreferences = null;
|
|||
|
|
|
|||
|
|
// ── 访问器 ──
|
|||
|
|
function getOnlineUsers() { return onlineUsers; }
|
|||
|
|
function setOnlineUsers(v) {
|
|||
|
|
onlineUsers = v;
|
|||
|
|
window.onlineUsers = onlineUsers;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getAutoScroll() { return autoScroll; }
|
|||
|
|
function setAutoScroll(v) { autoScroll = Boolean(v); }
|
|||
|
|
|
|||
|
|
function getMaxMsgId() { return maxMsgId; }
|
|||
|
|
function setMaxMsgId(v) { if (v > maxMsgId) maxMsgId = v; }
|
|||
|
|
|
|||
|
|
function getBlockedSystemSenders() { return blockedSystemSenders; }
|
|||
|
|
function setBlockedSystemSenders(v) { blockedSystemSenders = v; }
|
|||
|
|
|
|||
|
|
function getIsMutedUntil() { return isMutedUntil; }
|
|||
|
|
function setIsMutedUntil(v) { isMutedUntil = v; }
|
|||
|
|
|
|||
|
|
// ── 构建聊天状态对象 ──
|
|||
|
|
const chatState = {
|
|||
|
|
// 常量
|
|||
|
|
BLOCKABLE_SYSTEM_SENDERS,
|
|||
|
|
BLOCKED_SYSTEM_SENDERS_STORAGE_KEY,
|
|||
|
|
CHAT_SOUND_MUTED_STORAGE_KEY,
|
|||
|
|
PUBLIC_MESSAGE_NODE_LIMIT,
|
|||
|
|
PRIVATE_MESSAGE_NODE_LIMIT,
|
|||
|
|
CHAT_MESSAGE_FLUSH_BATCH_SIZE,
|
|||
|
|
ROOMS_ONLINE_STATUS_CACHE_TTL,
|
|||
|
|
HEARTBEAT_INTERVAL,
|
|||
|
|
SYSTEM_USERS,
|
|||
|
|
ACTION_TEXT_MAP,
|
|||
|
|
MAX_HEARTBEAT_FAILS,
|
|||
|
|
|
|||
|
|
// DOM 引用
|
|||
|
|
get container() { return getContainer(); },
|
|||
|
|
get container2() { return getContainer2(); },
|
|||
|
|
get userList() { return getUserList(); },
|
|||
|
|
get toUserSelect() { return getToUserSelect(); },
|
|||
|
|
get onlineCount() { return getOnlineCount(); },
|
|||
|
|
get onlineCountBottom() { return getOnlineCountBottom(); },
|
|||
|
|
|
|||
|
|
// 在线用户
|
|||
|
|
get onlineUsers() { return onlineUsers; },
|
|||
|
|
set onlineUsers(v) {
|
|||
|
|
onlineUsers = v;
|
|||
|
|
window.onlineUsers = onlineUsers;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 自动滚屏
|
|||
|
|
get autoScroll() { return autoScroll; },
|
|||
|
|
set autoScroll(v) { autoScroll = Boolean(v); },
|
|||
|
|
|
|||
|
|
// 最大消息 ID
|
|||
|
|
get maxMsgId() { return maxMsgId; },
|
|||
|
|
set maxMsgId(v) { maxMsgId = v; },
|
|||
|
|
trackMaxMsgId(v) { if (v > maxMsgId) maxMsgId = v; },
|
|||
|
|
|
|||
|
|
// 消息队列
|
|||
|
|
get pendingChatMessages() { return pendingChatMessages; },
|
|||
|
|
set pendingChatMessages(v) { pendingChatMessages = v; },
|
|||
|
|
get chatMessageFlushTimer() { return chatMessageFlushTimer; },
|
|||
|
|
set chatMessageFlushTimer(v) { chatMessageFlushTimer = v; },
|
|||
|
|
|
|||
|
|
// 用户列表渲染
|
|||
|
|
get userListRenderTimer() { return userListRenderTimer; },
|
|||
|
|
set userListRenderTimer(v) { userListRenderTimer = v; },
|
|||
|
|
get userFilterRenderTimer() { return userFilterRenderTimer; },
|
|||
|
|
set userFilterRenderTimer(v) { userFilterRenderTimer = v; },
|
|||
|
|
get userBadgeRotationTick() { return userBadgeRotationTick; },
|
|||
|
|
set userBadgeRotationTick(v) { userBadgeRotationTick = v; },
|
|||
|
|
|
|||
|
|
// 存点节点
|
|||
|
|
get lastAutosaveNode() { return lastAutosaveNode; },
|
|||
|
|
set lastAutosaveNode(v) { lastAutosaveNode = v; },
|
|||
|
|
|
|||
|
|
// 房间在线状态缓存
|
|||
|
|
get roomsRefreshTimer() { return roomsRefreshTimer; },
|
|||
|
|
set roomsRefreshTimer(v) { roomsRefreshTimer = v; },
|
|||
|
|
get roomsOnlineStatusCache() { return roomsOnlineStatusCache; },
|
|||
|
|
set roomsOnlineStatusCache(v) { roomsOnlineStatusCache = v; },
|
|||
|
|
get roomsOnlineStatusCacheAt() { return roomsOnlineStatusCacheAt; },
|
|||
|
|
set roomsOnlineStatusCacheAt(v) { roomsOnlineStatusCacheAt = v; },
|
|||
|
|
|
|||
|
|
// 禁言
|
|||
|
|
get isMutedUntil() { return isMutedUntil; },
|
|||
|
|
set isMutedUntil(v) { isMutedUntil = v; },
|
|||
|
|
|
|||
|
|
// 发送锁
|
|||
|
|
get imeComposing() { return imeComposing; },
|
|||
|
|
set imeComposing(v) { imeComposing = v; },
|
|||
|
|
get isSending() { return isSending; },
|
|||
|
|
set isSending(v) { isSending = v; },
|
|||
|
|
get sendStartedAt() { return sendStartedAt; },
|
|||
|
|
set sendStartedAt(v) { sendStartedAt = v; },
|
|||
|
|
|
|||
|
|
// 退出房间
|
|||
|
|
get leaveRequestInFlight() { return leaveRequestInFlight; },
|
|||
|
|
set leaveRequestInFlight(v) { leaveRequestInFlight = v; },
|
|||
|
|
|
|||
|
|
// 心跳计数
|
|||
|
|
get heartbeatFailCount() { return heartbeatFailCount; },
|
|||
|
|
set heartbeatFailCount(v) { heartbeatFailCount = v; },
|
|||
|
|
|
|||
|
|
// 偏好
|
|||
|
|
get blockedSystemSenders() { return blockedSystemSenders; },
|
|||
|
|
set blockedSystemSenders(v) { blockedSystemSenders = v; },
|
|||
|
|
get initialChatPreferences() { return initialChatPreferences; },
|
|||
|
|
set initialChatPreferences(v) { initialChatPreferences = v; },
|
|||
|
|
|
|||
|
|
// 重置所有状态(用于测试或强制同步)
|
|||
|
|
reset() {
|
|||
|
|
onlineUsers = {};
|
|||
|
|
window.onlineUsers = onlineUsers;
|
|||
|
|
autoScroll = true;
|
|||
|
|
maxMsgId = 0;
|
|||
|
|
pendingChatMessages = [];
|
|||
|
|
chatMessageFlushTimer = null;
|
|||
|
|
userListRenderTimer = null;
|
|||
|
|
userFilterRenderTimer = null;
|
|||
|
|
userBadgeRotationTick = 0;
|
|||
|
|
lastAutosaveNode = null;
|
|||
|
|
roomsRefreshTimer = null;
|
|||
|
|
roomsOnlineStatusCache = null;
|
|||
|
|
roomsOnlineStatusCacheAt = 0;
|
|||
|
|
isMutedUntil = 0;
|
|||
|
|
imeComposing = false;
|
|||
|
|
isSending = false;
|
|||
|
|
sendStartedAt = 0;
|
|||
|
|
leaveRequestInFlight = false;
|
|||
|
|
heartbeatFailCount = 0;
|
|||
|
|
blockedSystemSenders = new Set();
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 挂载到 window 供 Blade 脚本及其他模块使用
|
|||
|
|
window.chatState = chatState;
|
|||
|
|
|
|||
|
|
// 向后兼容 Blade 中已暴露的 window 接口
|
|||
|
|
export function hydrateOnlineUserPayload(username, payload) {
|
|||
|
|
const nextPayload = { ...(onlineUsers[username] || {}) };
|
|||
|
|
// 清除旧状态字段
|
|||
|
|
delete nextPayload.daily_status_key;
|
|||
|
|
delete nextPayload.daily_status_label;
|
|||
|
|
delete nextPayload.daily_status_icon;
|
|||
|
|
delete nextPayload.daily_status_group;
|
|||
|
|
delete nextPayload.daily_status_expires_at;
|
|||
|
|
onlineUsers[username] = { ...nextPayload, ...payload };
|
|||
|
|
window.onlineUsers = onlineUsers;
|
|||
|
|
}
|
|||
|
|
window.hydrateOnlineUserPayload = hydrateOnlineUserPayload;
|
|||
|
|
|
|||
|
|
export function renderUserList() {
|
|||
|
|
// 占位:实际渲染逻辑由 user-list.js 挂载到 window.chatState.renderUserList
|
|||
|
|
if (typeof window.renderUserList === "function") {
|
|||
|
|
window.renderUserList();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export { onlineUsers, autoScroll, maxMsgId };
|