修复聊天室字号偏好和游戏通知显示
This commit is contained in:
@@ -240,7 +240,7 @@ a:hover {
|
||||
}
|
||||
|
||||
.msg-line .msg-time {
|
||||
font-size: 9px;
|
||||
font-size: 0.72em;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ a:hover {
|
||||
.msg-line.sys-msg {
|
||||
color: #cc0000;
|
||||
text-align: center;
|
||||
font-size: 9pt;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* ── 底部输入工具栏 ─────────────────────────────── */
|
||||
|
||||
@@ -216,7 +216,7 @@ import { initChatImageLightboxEvents, closeChatImageLightbox, openChatImageLight
|
||||
import { bindRoomStatusControls, normalizeRoomStatus, renderRoomStatusRow, renderRoomsOnlineStatus, renderRoomsOnlineStatusToContainer, resolveRoomUrl } from "./chat-room/rooms.js";
|
||||
import { bindChatRightPanelControls } from "./chat-room/right-panel.js";
|
||||
import { bindChatImageUploadControl } from "./chat-room/image-upload.js";
|
||||
import { applyFontSize, bindChatFontSizeControl, CHAT_FONT_SIZE_STORAGE_KEY, restoreChatFontSize } from "./chat-room/font-size.js";
|
||||
import { applyFontSize, bindChatFontSizeControl, CHAT_DEFAULT_FONT_SIZE, CHAT_FONT_SIZE_STORAGE_KEY, restoreChatFontSize } from "./chat-room/font-size.js";
|
||||
import { bindAppointmentAnnouncementControls, showAppointmentBanner } from "./chat-room/appointment-announcement.js";
|
||||
import { bindChatBanner } from "./chat-room/banner.js";
|
||||
import { bindChatBotControls, clearChatBotContext, sendToChatBot } from "./chat-room/chat-bot.js";
|
||||
@@ -461,6 +461,7 @@ if (typeof window !== "undefined") {
|
||||
sendToChatBot,
|
||||
applyFontSize,
|
||||
bindChatFontSizeControl,
|
||||
CHAT_DEFAULT_FONT_SIZE,
|
||||
CHAT_FONT_SIZE_STORAGE_KEY,
|
||||
restoreChatFontSize,
|
||||
bindChatImageUploadControl,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { enqueueChatMessage } from "./message-renderer.js";
|
||||
// ── 事件注册标记 ──
|
||||
let chatEventsBound = false;
|
||||
let chatWebSocketInitRetryTimer = null;
|
||||
const GOMOKU_INVITE_BUTTON_FONT_SIZE = "0.82em";
|
||||
|
||||
// ── 辅助函数 ──
|
||||
function csrf() {
|
||||
@@ -235,13 +236,13 @@ function setupGomokuInviteListener() {
|
||||
const acceptBtn = isSelf
|
||||
? `<button type="button" data-gomoku-open-panel class="gomoku-invite-open"
|
||||
style="margin-left:10px; padding:3px 12px; border:1.5px solid #2d6096;
|
||||
border-radius:12px; background:#f0f6ff; color:#2d6096; font-size:12px;
|
||||
border-radius:12px; background:#f0f6ff; color:#2d6096; font-size:${GOMOKU_INVITE_BUTTON_FONT_SIZE};
|
||||
cursor:pointer; font-family:inherit; transition:all .15s;">
|
||||
⤴️ 打开面板
|
||||
</button>`
|
||||
: `<button type="button" data-gomoku-accept-id="${gomokuGameId}" id="gomoku-accept-${gomokuGameId}" class="gomoku-invite-accept"
|
||||
style="margin-left:10px; padding:3px 12px; border:1.5px solid #336699;
|
||||
border-radius:12px; background:#336699; color:#fff; font-size:12px;
|
||||
border-radius:12px; background:#336699; color:#fff; font-size:${GOMOKU_INVITE_BUTTON_FONT_SIZE};
|
||||
cursor:pointer; font-family:inherit; transition:opacity .15s;">
|
||||
⚔️ 接受挑战
|
||||
</button>`;
|
||||
|
||||
@@ -10,6 +10,8 @@ let autoFishing = false;
|
||||
let autoFishCooldownTimer = null;
|
||||
let autoFishCooldownCountdown = null;
|
||||
let fishingCastPending = false;
|
||||
const FISHING_MESSAGE_META_FONT_SIZE = "0.78em";
|
||||
const FISHING_MESSAGE_BODY_FONT_SIZE = "1em";
|
||||
|
||||
/**
|
||||
* 读取 CSRF Token。
|
||||
@@ -432,6 +434,13 @@ export async function startFishing() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (autoFishing && response.status === 409) {
|
||||
// 多标签页或重复自动抛竿时,后端会保留先到的 token,当前页等待后再接管。
|
||||
appendFishingMessage(`<span style="color:#d97706;">【钓鱼】${escapeHtml(data.message || "已有钓鱼正在进行,稍后自动重试。")}</span><span class="msg-time">(${timeText()})</span>`);
|
||||
startAutoFishingCooldown(Math.max(1, Number(data.retry_after) || 5));
|
||||
return;
|
||||
}
|
||||
|
||||
window.chatDialog?.alert?.(data.message || "钓鱼失败", "操作失败", "#cc4444");
|
||||
setFishingButton("🎣 钓鱼", false);
|
||||
return;
|
||||
@@ -460,7 +469,7 @@ export async function startFishing() {
|
||||
if (data.auto_fishing) {
|
||||
showAutoFishStopButton(0);
|
||||
updateAutoFishStopButtonCountdown(0, "自动收竿中 · 可拖动");
|
||||
appendFishingMessage(`<span style="color:#7c3aed;font-weight:bold;">🎣 自动钓鱼卡生效!自动收竿中... <span style="font-size:10px;opacity:0.7">(剩余${Number(data.auto_fishing_minutes_left) || 0}分钟)</span></span>`);
|
||||
appendFishingMessage(`<span style="color:#7c3aed;font-weight:bold;">🎣 自动钓鱼卡生效!自动收竿中... <span style="font-size:${FISHING_MESSAGE_META_FONT_SIZE};opacity:0.7">(剩余${Number(data.auto_fishing_minutes_left) || 0}分钟)</span></span>`);
|
||||
fishingReelTimeout = window.setTimeout(() => {
|
||||
removeBobber();
|
||||
void reelFish();
|
||||
@@ -468,7 +477,7 @@ export async function startFishing() {
|
||||
return;
|
||||
}
|
||||
|
||||
appendFishingMessage('<span style="color:#d97706;font-weight:bold;font-size:14px;">🐟 鱼上钩了!快点击屏幕上的浮漂!</span>');
|
||||
appendFishingMessage(`<span style="color:#d97706;font-weight:bold;font-size:${FISHING_MESSAGE_BODY_FONT_SIZE};">🐟 鱼上钩了!快点击屏幕上的浮漂!</span>`);
|
||||
setFishingButton("🎣 点击浮漂!", true);
|
||||
bobber.addEventListener("click", () => {
|
||||
removeBobber();
|
||||
@@ -530,7 +539,7 @@ export async function reelFish() {
|
||||
const color = Number(result.exp || 0) >= 0 ? "#16a34a" : "#dc2626";
|
||||
appendFishingMessage(
|
||||
`<span style="color:${color};font-weight:bold;">${escapeHtml(result.emoji || "🎣")}【钓鱼结果】</span>${escapeHtml(result.message || "")}` +
|
||||
` <span style="color:#666;font-size:11px;">(经验:${Number(data.exp_num) || 0} 金币:${Number(data.jjb) || 0})</span>` +
|
||||
` <span style="color:#666;font-size:${FISHING_MESSAGE_META_FONT_SIZE};">(经验:${Number(data.exp_num) || 0} 金币:${Number(data.jjb) || 0})</span>` +
|
||||
`<span class="msg-time">(${timeText()})</span>`,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,17 +1,69 @@
|
||||
// 聊天室字号偏好控制,保留旧的 localStorage key 以兼容已有用户设置。
|
||||
|
||||
export const CHAT_FONT_SIZE_STORAGE_KEY = "chat_font_size";
|
||||
export const CHAT_DEFAULT_FONT_SIZE = 13;
|
||||
export const CHAT_FONT_SIZE_MIN = 10;
|
||||
export const CHAT_FONT_SIZE_MAX = 30;
|
||||
let fontSizeEventsBound = false;
|
||||
|
||||
/**
|
||||
* 应用字号到聊天消息窗口,并保存到 localStorage。
|
||||
* 规整聊天室字号,过滤非法或越界的旧缓存值。
|
||||
*
|
||||
* @param {unknown} size 字号大小
|
||||
* @returns {number|null}
|
||||
*/
|
||||
export function normalizeChatFontSize(size) {
|
||||
const px = Number.parseInt(String(size ?? ""), 10);
|
||||
|
||||
if (Number.isNaN(px) || px < CHAT_FONT_SIZE_MIN || px > CHAT_FONT_SIZE_MAX) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步底部输入框上方工具按钮字号。
|
||||
*
|
||||
* @param {number} px 用户选择的聊天字号
|
||||
* @returns {void}
|
||||
*/
|
||||
function applyInputToolbarFontSize(px) {
|
||||
const toolbarRow = document.querySelector("#chat-form > .input-row");
|
||||
if (!(toolbarRow instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fontSize = `${px}px`;
|
||||
toolbarRow.style.fontSize = fontSize;
|
||||
toolbarRow.style.fontFamily = "inherit";
|
||||
toolbarRow.style.lineHeight = "1.2";
|
||||
toolbarRow.querySelectorAll([
|
||||
":scope > label",
|
||||
":scope > label select",
|
||||
":scope > label input",
|
||||
":scope > button",
|
||||
":scope > div > button",
|
||||
"#feature-menu button",
|
||||
"#admin-menu button",
|
||||
].join(",")).forEach((control) => {
|
||||
control.style.fontFamily = "inherit";
|
||||
control.style.fontSize = "inherit";
|
||||
control.style.lineHeight = "1.2";
|
||||
control.style.fontWeight = "400";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用字号到聊天消息窗口和输入栏工具按钮,并保存到 localStorage。
|
||||
*
|
||||
* @param {string|number} size 字号大小
|
||||
* @param {{syncContext?:boolean}} options 同步选项
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function applyFontSize(size) {
|
||||
const px = Number.parseInt(size, 10);
|
||||
if (Number.isNaN(px) || px < 10 || px > 30) {
|
||||
export function applyFontSize(size, options = {}) {
|
||||
const px = normalizeChatFontSize(size);
|
||||
if (px === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,8 +75,15 @@ export function applyFontSize(size) {
|
||||
if (privateContainer) {
|
||||
privateContainer.style.fontSize = `${px}px`;
|
||||
}
|
||||
applyInputToolbarFontSize(px);
|
||||
|
||||
localStorage.setItem(CHAT_FONT_SIZE_STORAGE_KEY, String(px));
|
||||
if (options.syncContext !== false && window.chatContext && typeof window.chatContext === "object") {
|
||||
window.chatContext.chatPreferences = {
|
||||
...(window.chatContext.chatPreferences || {}),
|
||||
font_size: px,
|
||||
};
|
||||
}
|
||||
|
||||
const selector = document.getElementById("font_size_select");
|
||||
if (selector) {
|
||||
@@ -35,14 +94,16 @@ export function applyFontSize(size) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 localStorage 恢复已保存的聊天室字号。
|
||||
* 从账号偏好或 localStorage 恢复已保存的聊天室字号。
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function restoreChatFontSize() {
|
||||
const saved = localStorage.getItem(CHAT_FONT_SIZE_STORAGE_KEY);
|
||||
const serverFontSize = normalizeChatFontSize(window.chatContext?.chatPreferences?.font_size);
|
||||
const localFontSize = normalizeChatFontSize(localStorage.getItem(CHAT_FONT_SIZE_STORAGE_KEY));
|
||||
const saved = serverFontSize ?? localFontSize ?? CHAT_DEFAULT_FONT_SIZE;
|
||||
|
||||
return saved ? applyFontSize(saved) : false;
|
||||
return applyFontSize(saved, { syncContext: serverFontSize !== null });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +122,8 @@ export function bindChatFontSizeControl() {
|
||||
return;
|
||||
}
|
||||
|
||||
applyFontSize(event.target.value);
|
||||
if (applyFontSize(event.target.value)) {
|
||||
void window.saveChatPreferences?.();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,6 +23,14 @@ import {
|
||||
|
||||
// ── 游戏标签判断 ──
|
||||
const GAME_LABEL_PREFIXES = ["五子棋", "双色球", "钓鱼", "老虎机", "百家乐", "赛马"];
|
||||
const CHAT_NOTICE_CHIP_FONT_SIZE = "0.82em";
|
||||
const CHAT_NOTICE_META_FONT_SIZE = "0.72em";
|
||||
const CHAT_NOTICE_BUTTON_FONT_SIZE = "0.82em";
|
||||
const CHAT_NOTICE_BODY_FONT_SIZE = "1em";
|
||||
const CHAT_NOTICE_ICON_FONT_SIZE = "1.08em";
|
||||
const CHAT_NOTICE_LARGE_ICON_FONT_SIZE = "1.35em";
|
||||
const CHAT_NOTICE_DECOR_ICON_FONT_SIZE = "4.25em";
|
||||
|
||||
function isGameLabel(name) {
|
||||
if (GAME_LABEL_PREFIXES.some((p) => name.startsWith(p))) return true;
|
||||
if (name.includes(" ")) return true;
|
||||
@@ -60,7 +68,7 @@ function parseBracketUsers(content, color = "#000099") {
|
||||
* 构建统一的猜谜活动标题与题型标签。
|
||||
*/
|
||||
function buildGameLabelChipHtml(label, accentColor) {
|
||||
return `<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor};color:#fff;font-size:11px;font-weight:700;line-height:1;border:1px solid ${accentColor};">${escapeHtml(label)}</span>`;
|
||||
return `<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor};color:#fff;font-size:${CHAT_NOTICE_CHIP_FONT_SIZE};font-weight:700;line-height:1;border:1px solid ${accentColor};">${escapeHtml(label)}</span>`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,19 +123,19 @@ function buildRedPacketAnnouncementHtml(msg, timeStr) {
|
||||
.trim();
|
||||
|
||||
const summary = escapeHtml(textOnlyContent);
|
||||
const actionButtonHtml = `<button type="button"${buttonOnclick ? ` onclick="${escapeHtml(buttonOnclick)}"` : ""} style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor};color:#fff;font-size:11px;font-weight:700;line-height:1;border:1px solid ${accentColor};cursor:pointer;box-shadow:none;vertical-align:middle;">${escapeHtml(buttonLabel)}</button>`;
|
||||
const actionButtonHtml = `<button type="button"${buttonOnclick ? ` onclick="${escapeHtml(buttonOnclick)}"` : ""} style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor};color:#fff;font-size:${CHAT_NOTICE_BUTTON_FONT_SIZE};font-weight:700;line-height:1;border:1px solid ${accentColor};cursor:pointer;box-shadow:none;vertical-align:middle;">${escapeHtml(buttonLabel)}</button>`;
|
||||
|
||||
return `
|
||||
<div style="display:flex;align-items:center;gap:7px;padding:5px 9px;border-radius:11px;background:${colorPalette.softBackground};border:1px solid ${colorPalette.softBorder};box-shadow:0 4px 12px rgba(15,23,42,.045);overflow:hidden;">
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${accentColor};display:flex;align-items:center;justify-content:center;color:#fff;font-size:13px;box-shadow:0 2px 6px ${colorPalette.softBorder};flex-shrink:0;">${icon}</div>
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${accentColor};display:flex;align-items:center;justify-content:center;color:#fff;font-size:${CHAT_NOTICE_ICON_FONT_SIZE};box-shadow:0 2px 6px ${colorPalette.softBorder};flex-shrink:0;">${icon}</div>
|
||||
<div style="min-width:0;flex:1;display:flex;align-items:center;gap:7px;flex-wrap:wrap;color:${colorPalette.text};">
|
||||
<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;flex-shrink:0;">
|
||||
${buildGameLabelChipHtml("礼包红包", accentColor)}
|
||||
<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${colorPalette.chipBackground};color:${colorPalette.chipText};font-size:11px;font-weight:700;line-height:1;border:1px solid ${colorPalette.chipBorder};">${escapeHtml(typeLabel)}</span>
|
||||
<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${colorPalette.chipBackground};color:${colorPalette.chipText};font-size:${CHAT_NOTICE_CHIP_FONT_SIZE};font-weight:700;line-height:1;border:1px solid ${colorPalette.chipBorder};">${escapeHtml(typeLabel)}</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:12px;line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<span>${summary}</span>
|
||||
<span class="msg-time" style="font-size:10px;color:#94a3b8;">(${timeStr})</span>
|
||||
<span class="msg-time" style="font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;">(${timeStr})</span>
|
||||
${actionButtonHtml}
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,7 +152,7 @@ function buildQuizBadgeHtml(msg, accentColor = "#7c3aed") {
|
||||
return `
|
||||
<span style="display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;">
|
||||
${buildGameLabelChipHtml(activityLabel, accentColor)}
|
||||
<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor}1A;color:${accentColor};font-size:11px;font-weight:700;line-height:1;border:1px solid ${accentColor}33;">${escapeHtml(typeLabel)}</span>
|
||||
<span style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:${accentColor}1A;color:${accentColor};font-size:${CHAT_NOTICE_CHIP_FONT_SIZE};font-weight:700;line-height:1;border:1px solid ${accentColor}33;">${escapeHtml(typeLabel)}</span>
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
@@ -373,7 +381,7 @@ function normalizeSystemGameCardActions(content, meta) {
|
||||
const onclickAttr = onclickMatch ? ` onclick="${escapeHtml(onclickMatch[2])}"` : "";
|
||||
const safeLabel = String(label || "").trim();
|
||||
|
||||
return `<button type="button"${onclickAttr} style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:#fff;color:${meta.accent};font-size:11px;font-weight:700;line-height:1;border:1px solid ${meta.accent};cursor:pointer;box-shadow:none;vertical-align:middle;">${safeLabel}</button>`;
|
||||
return `<button type="button"${onclickAttr} style="display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;background:#fff;color:${meta.accent};font-size:${CHAT_NOTICE_BUTTON_FONT_SIZE};font-weight:700;line-height:1;border:1px solid ${meta.accent};cursor:pointer;box-shadow:none;vertical-align:middle;">${safeLabel}</button>`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -391,12 +399,12 @@ function buildSystemGameNotificationHtml(msg, timeStr) {
|
||||
|
||||
return `
|
||||
<div style="display:flex;align-items:center;gap:7px;padding:5px 9px;border-radius:11px;background:${meta.background};border:1px solid ${meta.border};box-shadow:0 4px 12px rgba(15,23,42,.045);overflow:hidden;">
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${meta.accent};display:flex;align-items:center;justify-content:center;color:#fff;font-size:13px;box-shadow:0 2px 6px ${meta.border};flex-shrink:0;">${meta.icon}</div>
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${meta.accent};display:flex;align-items:center;justify-content:center;color:#fff;font-size:${CHAT_NOTICE_ICON_FONT_SIZE};box-shadow:0 2px 6px ${meta.border};flex-shrink:0;">${meta.icon}</div>
|
||||
<div style="min-width:0;flex:1;display:flex;align-items:center;gap:7px;flex-wrap:wrap;color:${meta.text};">
|
||||
${buildGameLabelChipHtml(meta.label, meta.accent)}
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:12px;line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<span>${parseBracketUsers(summary, meta.text)}</span>
|
||||
<span class="msg-time" style="font-size:10px;color:#94a3b8;font-weight:600;">(${timeStr})</span>
|
||||
<span class="msg-time" style="font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;font-weight:600;">(${timeStr})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -420,15 +428,15 @@ function buildQuizStartHtml(msg, timeStr) {
|
||||
|
||||
return `
|
||||
<div style="display:flex;align-items:center;gap:7px;padding:5px 9px;border-radius:11px;background:linear-gradient(135deg,#f5f3ff,#faf5ff);border:1px solid rgba(124,58,237,.16);box-shadow:0 4px 12px rgba(124,58,237,.07);overflow:hidden;">
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:linear-gradient(135deg,#7c3aed,#a78bfa);display:flex;align-items:center;justify-content:center;color:#fff;font-size:13px;box-shadow:0 2px 6px rgba(124,58,237,.16);flex-shrink:0;">🧩</div>
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:linear-gradient(135deg,#7c3aed,#a78bfa);display:flex;align-items:center;justify-content:center;color:#fff;font-size:${CHAT_NOTICE_ICON_FONT_SIZE};box-shadow:0 2px 6px rgba(124,58,237,.16);flex-shrink:0;">🧩</div>
|
||||
<div style="min-width:0;flex:1;display:flex;align-items:center;gap:7px;flex-wrap:wrap;color:#312e81;">
|
||||
<div style="display:flex;align-items:center;gap:7px;flex-wrap:wrap;flex-shrink:0;">${buildQuizBadgeHtml(msg)}</div>
|
||||
<div data-quiz-inline-text style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:12px;line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<div data-quiz-inline-text style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<span>${safeHint}</span>
|
||||
<span class="msg-time" style="font-size:10px;color:#94a3b8;">(${timeStr})</span>
|
||||
<span class="msg-time" style="font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;">(${timeStr})</span>
|
||||
<span data-quiz-inline-action-anchor></span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;color:#6d28d9;font-size:10px;flex-shrink:0;margin-left:auto;">
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;color:#6d28d9;font-size:${CHAT_NOTICE_META_FONT_SIZE};flex-shrink:0;margin-left:auto;">
|
||||
<span style="padding:1px 6px;border-radius:999px;background:#ffffff;box-shadow:inset 0 0 0 1px rgba(124,58,237,.10);white-space:nowrap;">💰 ${quizMeta.rewardGold} 金币</span>
|
||||
<span style="padding:1px 6px;border-radius:999px;background:#ffffff;box-shadow:inset 0 0 0 1px rgba(124,58,237,.10);white-space:nowrap;">⭐ ${quizMeta.rewardExp} 经验</span>
|
||||
</div>
|
||||
@@ -478,15 +486,15 @@ function buildQuizResultHtml(msg, timeStr) {
|
||||
|
||||
return `
|
||||
<div style="display:flex;align-items:center;gap:7px;padding:5px 9px;border-radius:11px;background:${accentBackground};border:1px solid ${accentBorder};box-shadow:0 4px 12px rgba(15,23,42,.045);overflow:hidden;">
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${iconBackground};display:flex;align-items:center;justify-content:center;color:#fff;font-size:13px;box-shadow:0 2px 6px ${accentBorder};flex-shrink:0;">${icon}</div>
|
||||
<div style="width:23px;height:23px;border-radius:7px;background:${iconBackground};display:flex;align-items:center;justify-content:center;color:#fff;font-size:${CHAT_NOTICE_ICON_FONT_SIZE};box-shadow:0 2px 6px ${accentBorder};flex-shrink:0;">${icon}</div>
|
||||
<div style="min-width:0;flex:1;display:flex;align-items:center;gap:7px;flex-wrap:wrap;color:${textColor};">
|
||||
<div style="display:flex;align-items:center;gap:7px;flex-wrap:wrap;flex-shrink:0;">${buildQuizBadgeHtml(msg, badgeColor)}</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:12px;line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};line-height:1.25;font-weight:700;min-width:200px;flex:1;">
|
||||
<span>${summaryHtml}</span>
|
||||
<span class="msg-time" style="font-size:10px;color:#94a3b8;">(${timeStr})</span>
|
||||
<span class="msg-time" style="font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;">(${timeStr})</span>
|
||||
</div>
|
||||
${isAnsweredResult ? `
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;color:${textColor};font-size:10px;flex-shrink:0;margin-left:auto;">
|
||||
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;color:${textColor};font-size:${CHAT_NOTICE_META_FONT_SIZE};flex-shrink:0;margin-left:auto;">
|
||||
<span style="padding:1px 6px;border-radius:999px;background:#ffffff;box-shadow:inset 0 0 0 1px ${isAnsweredResult ? "rgba(124,58,237,.10)" : "rgba(217,119,6,.12)"};white-space:nowrap;">💰 ${quizMeta.rewardGold} 金币</span>
|
||||
<span style="padding:1px 6px;border-radius:999px;background:#ffffff;box-shadow:inset 0 0 0 1px ${isAnsweredResult ? "rgba(124,58,237,.10)" : "rgba(217,119,6,.12)"};white-space:nowrap;">⭐ ${quizMeta.rewardExp} 经验</span>
|
||||
</div>
|
||||
@@ -546,7 +554,7 @@ export function buildChatMessageContent(msg, fontColor, textColorClass) {
|
||||
|
||||
return `
|
||||
<span style="display:inline-flex; align-items:center; gap:6px; vertical-align:middle;">
|
||||
<span style="display:inline-flex; align-items:center; padding:4px 8px; border:1px dashed #94a3b8; border-radius:999px; background:#f8fafc; color:#64748b; font-size:12px;">🖼️ 图片已过期</span>
|
||||
<span style="display:inline-flex; align-items:center; padding:4px 8px; border:1px dashed #94a3b8; border-radius:999px; background:#f8fafc; color:#64748b; font-size:${CHAT_NOTICE_BUTTON_FONT_SIZE};">🖼️ 图片已过期</span>
|
||||
${captionHtml}
|
||||
</span>
|
||||
`;
|
||||
@@ -682,16 +690,16 @@ export function appendMessage(msg, renderBatch = null) {
|
||||
|
||||
html = `
|
||||
<div style="display:flex;align-items:center;gap:12px;">
|
||||
<div style="width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg, ${accent}, #fbbf24);display:flex;align-items:center;justify-content:center;font-size:24px;box-shadow: 0 4px 12px ${accent}44; flex-shrink: 0;">${icon}</div>
|
||||
<div style="width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg, ${accent}, #fbbf24);display:flex;align-items:center;justify-content:center;font-size:${CHAT_NOTICE_LARGE_ICON_FONT_SIZE};box-shadow: 0 4px 12px ${accent}44; flex-shrink: 0;">${icon}</div>
|
||||
<div style="min-width:0;flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||||
<span style="font-size:13px;font-weight:900;letter-spacing:.05em;color:${accent}; text-shadow: 0.5px 0.5px 0px rgba(0,0,0,0.05);">${typeLabel}</span>
|
||||
<span style="font-size:13px;color:#475569;font-weight:bold;">${levelName}</span>
|
||||
<span style="font-size:11px;color:#94a3b8;">(${timeStr})</span>
|
||||
<span style="font-size:${CHAT_NOTICE_CHIP_FONT_SIZE};font-weight:900;letter-spacing:.05em;color:${accent}; text-shadow: 0.5px 0.5px 0px rgba(0,0,0,0.05);">${typeLabel}</span>
|
||||
<span style="font-size:${CHAT_NOTICE_CHIP_FONT_SIZE};color:#475569;font-weight:bold;">${levelName}</span>
|
||||
<span style="font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;">(${timeStr})</span>
|
||||
</div>
|
||||
<div style="margin-top:4px;font-size:15px;line-height:1.6;color:#1e293b;font-weight:500;">${safeText}</div>
|
||||
<div style="margin-top:4px;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};line-height:1.6;color:#1e293b;font-weight:500;">${safeText}</div>
|
||||
</div>
|
||||
<div style="position:absolute; right:-10px; bottom:-10px; font-size:60px; opacity:0.05; transform:rotate(-15deg); pointer-events:none;">${icon}</div>
|
||||
<div style="position:absolute; right:-10px; bottom:-10px; font-size:${CHAT_NOTICE_DECOR_ICON_FONT_SIZE}; opacity:0.05; transform:rotate(-15deg); pointer-events:none;">${icon}</div>
|
||||
</div>
|
||||
`;
|
||||
timeStrOverride = true;
|
||||
@@ -716,7 +724,7 @@ export function appendMessage(msg, renderBatch = null) {
|
||||
}
|
||||
}
|
||||
const parsedBody = parseBracketUsers(bodyPart, "#1d4ed8");
|
||||
html = `<div style="color: #1e40af;">💬 ${clickablePrefix}${parsedBody} <span style="color: #93c5fd; font-size: 11px; font-weight: normal;">(${timeStr})</span></div>`;
|
||||
html = `<div style="color: #1e40af;">💬 ${clickablePrefix}${parsedBody} <span style="color: #93c5fd; font-size: ${CHAT_NOTICE_META_FONT_SIZE}; font-weight: normal;">(${timeStr})</span></div>`;
|
||||
timeStrOverride = true;
|
||||
} else if (SYSTEM_USERS.includes(msg.from_user)) {
|
||||
if (msg.from_user === "系统公告") {
|
||||
@@ -727,7 +735,7 @@ export function appendMessage(msg, renderBatch = null) {
|
||||
div.style.cssText =
|
||||
"background: linear-gradient(135deg, #fef2f2, #fff1f2); border: 2px solid #ef4444; border-radius: 8px; padding: 10px 14px; margin: 6px 0; box-shadow: 0 3px 8px rgba(239,68,68,0.16);";
|
||||
const parsedContent = parseBracketUsers(msg.content, "#dc2626");
|
||||
html = `<div style="font-size: 18px; line-height: 1.75; font-weight: 800; color: #dc2626;">${parsedContent} <span style="color: #999; font-size: 14px; font-weight: 500;">(${timeStr})</span></div>`;
|
||||
html = `<div style="font-size: ${CHAT_NOTICE_BODY_FONT_SIZE}; line-height: 1.75; font-weight: 800; color: #dc2626;">${parsedContent} <span style="color: #999; font-size: ${CHAT_NOTICE_META_FONT_SIZE}; font-weight: 500;">(${timeStr})</span></div>`;
|
||||
timeStrOverride = true;
|
||||
}
|
||||
} else if (msg.from_user === "系统传音") {
|
||||
@@ -748,13 +756,13 @@ export function appendMessage(msg, renderBatch = null) {
|
||||
"background:linear-gradient(135deg,#fff7ed,#fffbeb);border:1px solid rgba(245,158,11,.28);border-left:4px solid #f59e0b;border-radius:12px;padding:8px 12px;margin:4px 0;box-shadow:0 10px 24px rgba(245,158,11,.14);";
|
||||
html = `
|
||||
<div style="display:flex;align-items:flex-start;gap:10px;">
|
||||
<div style="width:38px;height:38px;border-radius:12px;background:linear-gradient(135deg,#f59e0b,#f97316);display:flex;align-items:center;justify-content:center;color:#fff;font-size:20px;box-shadow:0 8px 18px rgba(249,115,22,.22);flex-shrink:0;">📣</div>
|
||||
<div style="width:38px;height:38px;border-radius:12px;background:linear-gradient(135deg,#f59e0b,#f97316);display:flex;align-items:center;justify-content:center;color:#fff;font-size:${CHAT_NOTICE_LARGE_ICON_FONT_SIZE};box-shadow:0 8px 18px rgba(249,115,22,.22);flex-shrink:0;">📣</div>
|
||||
<div style="min-width:0;flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||||
${buildQuizBadgeHtml(msg, "#d97706")}
|
||||
<span class="msg-time">(${timeStr})</span>
|
||||
</div>
|
||||
<div style="margin-top:7px;color:#9a3412;font-size:15px;font-weight:800;line-height:1.75;">${parseBracketUsers(content, "#b45309")}</div>
|
||||
<div style="margin-top:7px;color:#9a3412;font-size:${CHAT_NOTICE_BODY_FONT_SIZE};font-weight:800;line-height:1.75;">${parseBracketUsers(content, "#b45309")}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -792,7 +800,7 @@ export function appendMessage(msg, renderBatch = null) {
|
||||
} else if (msg.is_secret) {
|
||||
if (msg.from_user === "系统") {
|
||||
div.style.cssText =
|
||||
"background:#f0fdf4;border-left:3px solid #16a34a;border-radius:4px;padding:3px 8px;margin:2px 0;font-size:12px;";
|
||||
"background:#f0fdf4;border-left:3px solid #16a34a;border-radius:4px;padding:3px 8px;margin:2px 0;";
|
||||
html = `<span style="color:#16a34a;font-weight:bold;">📢 系统:</span><span style="color:#15803d;">${msg.content}</span>`;
|
||||
} else {
|
||||
const fromHtml = clickableUser(msg.from_user, "#cc00cc", nameClass);
|
||||
@@ -1059,7 +1067,7 @@ export function flushQueuedChatMessages() {
|
||||
const notice = document.createElement("div");
|
||||
notice.className = "msg-line msg-burst-notice";
|
||||
notice.style.cssText =
|
||||
"text-align:center;padding:6px 0;margin:4px 0;font-size:12px;color:#94a3b8;border-top:1px dashed #d1d5db;border-bottom:1px dashed #d1d5db;";
|
||||
`text-align:center;padding:6px 0;margin:4px 0;font-size:${CHAT_NOTICE_META_FONT_SIZE};color:#94a3b8;border-top:1px dashed #d1d5db;border-bottom:1px dashed #d1d5db;`;
|
||||
notice.textContent = `⏫ 省略了 ${dropped} 条系统通知`;
|
||||
container.appendChild(notice);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// 聊天室偏好与每日状态工具,承接从 Blade 内联脚本迁移出的纯数据规整逻辑。
|
||||
|
||||
import { CHAT_FONT_SIZE_STORAGE_KEY, normalizeChatFontSize } from "./font-size.js";
|
||||
|
||||
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";
|
||||
@@ -12,7 +14,7 @@ let blockMenuEventsBound = false;
|
||||
*
|
||||
* @param {Record<string, unknown>|null|undefined} raw
|
||||
* @param {string[]} blockableSystemSenders
|
||||
* @returns {{blocked_system_senders:string[],sound_muted:boolean}}
|
||||
* @returns {{blocked_system_senders:string[],sound_muted:boolean,font_size:number|null}}
|
||||
*/
|
||||
export function normalizeChatPreferences(raw, blockableSystemSenders = BLOCKABLE_SYSTEM_SENDERS) {
|
||||
// 服务端或旧本地缓存可能包含已下架发送者,规整时只保留当前白名单。
|
||||
@@ -23,6 +25,7 @@ export function normalizeChatPreferences(raw, blockableSystemSenders = BLOCKABLE
|
||||
return {
|
||||
blocked_system_senders: Array.from(new Set(blocked)),
|
||||
sound_muted: Boolean(raw?.sound_muted),
|
||||
font_size: normalizeChatFontSize(raw?.font_size),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -454,17 +457,19 @@ export function bindBlockMenuControls() {
|
||||
/**
|
||||
* 当前登录账号没有服务端偏好时,判断是否需要迁移旧本地偏好。
|
||||
*
|
||||
* @param {{blocked_system_senders?:string[],sound_muted?:boolean}} serverPreferences
|
||||
* @param {{blocked_system_senders?:string[],sound_muted?:boolean,font_size?:number|null}} serverPreferences
|
||||
* @param {string[]} localBlockedSenders
|
||||
* @param {boolean} localMuted
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function shouldMigrateLocalChatPreferences(serverPreferences, localBlockedSenders, localMuted) {
|
||||
// 只有服务端尚无偏好时才迁移旧本地设置,避免覆盖已同步的账号配置。
|
||||
const localFontSize = normalizeChatFontSize(localStorage.getItem(CHAT_FONT_SIZE_STORAGE_KEY));
|
||||
const hasServerPreferences = (serverPreferences?.blocked_system_senders || []).length > 0
|
||||
|| Boolean(serverPreferences?.sound_muted);
|
||||
|| Boolean(serverPreferences?.sound_muted)
|
||||
|| normalizeChatFontSize(serverPreferences?.font_size) !== null;
|
||||
|
||||
return !hasServerPreferences && (localBlockedSenders.length > 0 || localMuted);
|
||||
return !hasServerPreferences && (localBlockedSenders.length > 0 || localMuted || localFontSize !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,13 +585,19 @@ export function resolveBlockedSystemSenderKey(msg) {
|
||||
/**
|
||||
* 构建当前聊天室偏好快照。
|
||||
*
|
||||
* @returns {{blocked_system_senders:string[],sound_muted:boolean}}
|
||||
* @returns {{blocked_system_senders:string[],sound_muted:boolean,font_size:number|null}}
|
||||
*/
|
||||
export function buildChatPreferencesPayload() {
|
||||
const state = window.chatState;
|
||||
const selector = document.getElementById("font_size_select");
|
||||
const fontSize = normalizeChatFontSize(selector?.value)
|
||||
?? normalizeChatFontSize(localStorage.getItem(CHAT_FONT_SIZE_STORAGE_KEY))
|
||||
?? normalizeChatFontSize(window.chatContext?.chatPreferences?.font_size);
|
||||
|
||||
return {
|
||||
blocked_system_senders: state ? Array.from(state.blockedSystemSenders) : [],
|
||||
sound_muted: isSoundMuted(),
|
||||
font_size: fontSize,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ let currentRoundId = 0;
|
||||
let currentRoomId = 0;
|
||||
let currentQuizType = "idiom";
|
||||
const QUIZ_TYPES = ["idiom", "brain_teaser"];
|
||||
const QUIZ_INLINE_BUTTON_FONT_SIZE = "0.82em";
|
||||
const QUIZ_INLINE_META_FONT_SIZE = "0.78em";
|
||||
|
||||
/**
|
||||
* 兼容新旧字段,提取前端统一使用的猜谜活动回合信息。
|
||||
@@ -141,7 +143,7 @@ function buildIdiomAnswerButton(roundId, hint, rewardGold, rewardExp, typeLabel,
|
||||
btn.textContent = "🎯 立即答题";
|
||||
btn.style.cssText =
|
||||
"display:inline-flex;align-items:center;gap:4px;padding:2px 9px;background:linear-gradient(135deg,#7c3aed,#a78bfa);" +
|
||||
"color:#fff;border:1px solid #7c3aed;border-radius:999px;font-size:11px;cursor:pointer;" +
|
||||
`color:#fff;border:1px solid #7c3aed;border-radius:999px;font-size:${QUIZ_INLINE_BUTTON_FONT_SIZE};cursor:pointer;` +
|
||||
"font-weight:700;line-height:1;vertical-align:middle;box-shadow:0 2px 6px rgba(124,58,237,.14);";
|
||||
|
||||
return btn;
|
||||
@@ -195,7 +197,7 @@ function syncQuizWinnerLabel(button, winnerUsername = "") {
|
||||
const winnerLabel = existingLabel || document.createElement("span");
|
||||
winnerLabel.dataset.quizWinnerLabel = String(button.dataset.quizAnswerBtn || button.dataset.idiomAnswerBtn || "0");
|
||||
winnerLabel.textContent = `答对:${winnerUsername}`;
|
||||
winnerLabel.style.cssText = "margin-left:6px;font-size:11px;line-height:1.2;color:#64748b;font-weight:700;white-space:nowrap;";
|
||||
winnerLabel.style.cssText = `margin-left:6px;font-size:${QUIZ_INLINE_META_FONT_SIZE};line-height:1.2;color:#64748b;font-weight:700;white-space:nowrap;`;
|
||||
|
||||
if (!existingLabel) {
|
||||
button.insertAdjacentElement("afterend", winnerLabel);
|
||||
@@ -216,7 +218,7 @@ export function disableIdiomAnswerButtons(roundId = 0, endedText = "本回合已
|
||||
button.style.boxShadow = "none";
|
||||
button.style.opacity = ".92";
|
||||
button.style.padding = "2px 9px";
|
||||
button.style.fontSize = "11px";
|
||||
button.style.fontSize = QUIZ_INLINE_BUTTON_FONT_SIZE;
|
||||
button.style.lineHeight = "1";
|
||||
button.title = endedText;
|
||||
button.textContent = "已结束";
|
||||
@@ -242,7 +244,7 @@ function syncQuizAnswerButtons(activeRoundIds) {
|
||||
button.style.boxShadow = "0 2px 6px rgba(124,58,237,.14)";
|
||||
button.style.opacity = "1";
|
||||
button.style.padding = "2px 9px";
|
||||
button.style.fontSize = "11px";
|
||||
button.style.fontSize = QUIZ_INLINE_BUTTON_FONT_SIZE;
|
||||
button.style.lineHeight = "1";
|
||||
button.title = "";
|
||||
button.textContent = "🎯 立即答题";
|
||||
|
||||
Reference in New Issue
Block a user