完善猜成语过期与答题记录逻辑

This commit is contained in:
pllx
2026-04-29 10:32:12 +08:00
parent 2f9b2eed64
commit 5962d6d2b3
11 changed files with 685 additions and 115 deletions
+43 -1
View File
@@ -2,6 +2,7 @@
// 从 Blade 内联脚本 scripts.blade.php 迁移至 Vite 模块。
import { escapeHtml, normalizeSafeChatUrl } from "./html.js";
import { attachIdiomAnswerButton, removeIdiomAnswerButtons } from "./idiom-quiz.js";
import { isExpiredChatImageMessage } from "./message-utils.js";
import { normalizeDailyStatus, resolveBlockedSystemSenderKey } from "./preferences-status.js";
import { escapePresenceText } from "./vip-presence.js";
@@ -49,6 +50,21 @@ function parseBracketUsers(content, color = "#000099") {
});
}
/**
* 只保留包厢窗口最近几条猜成语答题记录,避免答题历史无限堆积。
*/
function prunePrivateIdiomResultMessages(targetContainer, maxRecords = 3) {
if (!targetContainer) {
return;
}
const nodes = Array.from(targetContainer.querySelectorAll('[data-idiom-result="1"]'));
while (nodes.length > maxRecords) {
const firstNode = nodes.shift();
firstNode?.remove();
}
}
/**
* 构建聊天消息的内容 HTML。
*/
@@ -172,6 +188,14 @@ export function appendMessage(msg, renderBatch = null) {
const iconImg = `<img src="/images/bugle.png" style="display:inline;width:16px;height:16px;vertical-align:middle;margin-right:2px;mix-blend-mode: multiply;" onerror="this.src='/images/headface/1.gif'">`;
const parsedContent = parseBracketUsers(msg.content);
html = `${iconImg} ${parsedContent}`;
} else if (msg.action === "idiom_result") {
div.dataset.idiomResult = "1";
const winnerUsername = String(msg.winner_username || "");
const winnerHtml = clickableUser(winnerUsername, "#16a34a");
const answerText = escapeHtml(String(msg.idiom_answer || ""));
const rewardGold = Number.parseInt(String(msg.idiom_result_reward_gold ?? msg.reward_gold ?? 0), 10);
const rewardExp = Number.parseInt(String(msg.idiom_result_reward_exp ?? msg.reward_exp ?? 0), 10);
html = `<span style="color:#16a34a;font-weight:bold;">🎉 【${winnerHtml}】率先答对成语「${answerText}」,获得 ${rewardGold} 金币、${rewardExp} 经验!</span>`;
} else if (msg.action === "vip_presence") {
const accent = msg.presence_color || "#f59e0b";
div.style.cssText =
@@ -300,6 +324,12 @@ export function appendMessage(msg, renderBatch = null) {
html += ` <span class="msg-time">(${timeStr})</span>`;
}
div.innerHTML = html;
attachIdiomAnswerButton(div, msg);
// 历史消息恢复或实时结算时,都立即移除对应回合的旧答题按钮。
if (Number.parseInt(String(msg.idiom_game_round_ended_id || "0"), 10) > 0) {
removeIdiomAnswerButtons(Number.parseInt(String(msg.idiom_game_round_ended_id), 10));
}
// 命中屏蔽规则时,消息仍保留在 DOM 中,便于取消屏蔽后立即恢复显示。
if (shouldHideByBlock) {
@@ -325,7 +355,8 @@ export function appendMessage(msg, renderBatch = null) {
}
// 路由规则:公众窗口(say1) — 别人的公聊消息;包厢窗口(say2) — 自己发的 + 悄悄话 + 对自己说的
const isRelatedToMe = isMe || msg.is_secret || msg.to_user === window.chatContext?.username;
const isIdiomWinnerHistory = msg.action === "idiom_result" && msg.winner_username === window.chatContext?.username;
const isRelatedToMe = isMe || msg.is_secret || msg.to_user === window.chatContext?.username || isIdiomWinnerHistory;
// 存点通知标记
const isAutoSave = (msg.from_user === "系统" || msg.from_user === "") &&
@@ -343,12 +374,18 @@ export function appendMessage(msg, renderBatch = null) {
renderBatch.privateFragment.appendChild(div);
renderBatch.shouldPrunePrivate = true;
renderBatch.shouldScrollPrivate = renderBatch.shouldScrollPrivate || state.autoScroll;
if (msg.action === "idiom_result") {
renderBatch.shouldPrunePrivateIdiomResults = true;
}
return;
}
const container2 = state.container2;
if (container2) {
container2.appendChild(div);
pruneMessageContainer(container2, PRIVATE_MESSAGE_NODE_LIMIT);
if (msg.action === "idiom_result") {
prunePrivateIdiomResultMessages(container2, 3);
}
if (state.autoScroll) {
container2.scrollTop = container2.scrollHeight;
}
@@ -398,6 +435,7 @@ export function createChatMessageRenderBatch() {
privateFragment: document.createDocumentFragment(),
shouldPrunePublic: false,
shouldPrunePrivate: false,
shouldPrunePrivateIdiomResults: false,
shouldScrollPublic: false,
shouldScrollPrivate: false,
};
@@ -429,6 +467,10 @@ export function commitChatMessageRenderBatch(renderBatch) {
const container2 = state.container2;
if (container2) pruneMessageContainer(container2, PRIVATE_MESSAGE_NODE_LIMIT);
}
if (renderBatch.shouldPrunePrivateIdiomResults) {
const container2 = state.container2;
if (container2) prunePrivateIdiomResultMessages(container2, 3);
}
if (renderBatch.shouldScrollPublic) {
const container = state.container;
if (container) container.scrollTop = container.scrollHeight;