f17f171f4b
迁移收尾修复:
- heartbeat.js: 移除 export { } 中重复的 startHeartbeat/stopHeartbeat(已通过 export function 导出)
- scripts.blade.php: 移除 JS 注释中的 {{ }} 避免 Blade 编译为 e() 导致 PHP 解析错误
- preferences-status.js: 补全 6 个缺失的 window.* 赋值(toggleBlockMenu/toggleFeatureMenu 等),
实现迁移中丢失的 updateDailyStatus/clearDailyStatus,修复 handleFeatureLocalClear 清屏回调
- toolbar.js: 补全 window.runFeatureShortcut 赋值
头像框样式修复(chat-decorations.css):
- z-index 互换:头像降至 1,框升至 3,使框边缘可遮挡头像外围
- 使用 CSS mask(radial-gradient)挖环形替代旧 ::before 实心圆遮挡方案
- clip-path: circle(50%) 硬裁剪确保圆形,不受 chat.css border-radius: 2px 覆盖
- 特异性提升至 .user-item .avatar-frame-wrapper .user-head
新 Vite 模块(从 Blade 迁移):
- chat-state.js / message-renderer.js / user-list.js / chat-events.js
- composer.js(重写)/ heartbeat.js / admin-commands.js
- vip-presence.js / chat-decorations.css
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 };
|