273 lines
9.1 KiB
JavaScript
273 lines
9.1 KiB
JavaScript
// 猜成语游戏前端模块
|
||
// 监听 IdiomGameStarted / IdiomGameAnswered 事件,提供答题弹窗功能
|
||
|
||
function csrf() {
|
||
return document.querySelector('meta[name="csrf-token"]')?.content ?? "";
|
||
}
|
||
|
||
let currentRoundId = 0;
|
||
let currentRoomId = 0;
|
||
|
||
/**
|
||
* 收到猜成语出题事件时,在聊天窗口显示提示消息。
|
||
*/
|
||
function handleIdiomGameStarted(e) {
|
||
const { round_id, hint, reward_gold, reward_exp, message } = e.detail || {};
|
||
if (!round_id || !hint) return;
|
||
|
||
currentRoundId = round_id;
|
||
currentRoomId = window.chatContext?.roomId || 0;
|
||
|
||
// 追加一条聊天室消息(由 MessageSent 事件负责渲染,不重复添加)
|
||
// 这里只存储当前回合信息
|
||
console.log(`猜成语开始:${hint},奖励 ${reward_gold}金/${reward_exp}经验`);
|
||
}
|
||
|
||
/**
|
||
* 收到猜成语结果事件。
|
||
*/
|
||
function handleIdiomGameAnswered(e) {
|
||
const { answer, winner_username, reward_gold, reward_exp, round_id } = e.detail || {};
|
||
if (!answer) return;
|
||
|
||
currentRoundId = 0;
|
||
|
||
// 关闭当前用户的答题弹窗(如果开着的话)
|
||
const answerModal = document.getElementById("idiom-answer-modal");
|
||
if (answerModal && answerModal.style.display !== "none") {
|
||
answerModal.style.display = "none";
|
||
}
|
||
|
||
// ── 分屏文字提示 ──
|
||
// 回答者 → 包厢(chat-messages-container2)
|
||
// 其他人 → 公屏(chat-messages-container)
|
||
const now = new Date();
|
||
const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
|
||
now.getMinutes().toString().padStart(2, "0") + ":" +
|
||
now.getSeconds().toString().padStart(2, "0");
|
||
|
||
const div = document.createElement("div");
|
||
div.className = "msg-line";
|
||
|
||
div.innerHTML = `<span style="color:#16a34a;font-weight:bold;">🎉 恭喜 <span class="msg-user" data-chat-message-user data-u="${winner_username}" style="color:#16a34a;cursor:pointer;border-bottom:1px dashed #16a34a;">${winner_username}</span> 率先答对成语「${answer}」,获得 ${reward_gold} 金币、${reward_exp} 经验!</span><span class="msg-time">(${timeStr})</span>`;
|
||
|
||
const isWinner = winner_username === (window.chatContext?.username || "");
|
||
if (isWinner) {
|
||
// 回答者 → 包厢
|
||
const say2 = document.getElementById("chat-messages-container2");
|
||
if (say2) {
|
||
say2.appendChild(div.cloneNode(true));
|
||
say2.scrollTop = say2.scrollHeight;
|
||
}
|
||
} else {
|
||
// 其他人 → 公屏
|
||
const say1 = document.getElementById("chat-messages-container");
|
||
if (say1) {
|
||
say1.appendChild(div);
|
||
say1.scrollTop = say1.scrollHeight;
|
||
}
|
||
}
|
||
|
||
// ── Toast 通知(所有用户都能看到) ──
|
||
window.chatToast?.show({
|
||
title: "🧩 猜成语",
|
||
message: `<b>${winner_username}</b> 答对了「${answer}」,获得 ${reward_gold}💰 + ${reward_exp}⭐!`,
|
||
icon: "🎉",
|
||
color: "#16a34a",
|
||
duration: 6000,
|
||
});
|
||
|
||
// ── 标记所有对应 round_id 的【答题】按钮为已答 ──
|
||
document.querySelectorAll(`[data-idiom-answer-btn="${round_id}"]`).forEach((btn) => {
|
||
btn.dataset.idiomAnswered = "1";
|
||
btn.textContent = "✅ 已答";
|
||
btn.style.background = "#9ca3af";
|
||
btn.style.cursor = "default";
|
||
btn.style.opacity = "0.6";
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 打开答题弹窗。
|
||
*/
|
||
function openIdiomAnswerModal(roundId, hint, rewardGold, rewardExp) {
|
||
currentRoundId = roundId;
|
||
currentRoomId = window.chatContext?.roomId || 0;
|
||
|
||
const modal = document.getElementById("idiom-answer-modal");
|
||
if (!modal) return;
|
||
|
||
const hintEl = document.getElementById("idiom-answer-hint");
|
||
const rewardEl = document.getElementById("idiom-answer-reward");
|
||
if (hintEl) hintEl.textContent = hint;
|
||
if (rewardEl) rewardEl.textContent = `🎁 答对奖励:${rewardGold} 金币 + ${rewardExp} 经验`;
|
||
|
||
modal.style.display = "flex";
|
||
|
||
const input = document.getElementById("idiom-answer-input");
|
||
if (input) {
|
||
input.value = "";
|
||
input.focus();
|
||
input.disabled = false;
|
||
}
|
||
|
||
const submitBtn = document.getElementById("idiom-answer-submit");
|
||
if (submitBtn) {
|
||
submitBtn.disabled = false;
|
||
submitBtn.textContent = "提交答案";
|
||
}
|
||
|
||
const feedbackEl = document.getElementById("idiom-answer-feedback");
|
||
if (feedbackEl) feedbackEl.textContent = "";
|
||
}
|
||
|
||
/**
|
||
* 关闭答题弹窗。
|
||
*/
|
||
function closeIdiomAnswerModal() {
|
||
const modal = document.getElementById("idiom-answer-modal");
|
||
if (modal) modal.style.display = "none";
|
||
}
|
||
|
||
/**
|
||
* 提交答案。
|
||
*/
|
||
async function submitIdiomAnswer() {
|
||
const input = document.getElementById("idiom-answer-input");
|
||
const feedbackEl = document.getElementById("idiom-answer-feedback");
|
||
const submitBtn = document.getElementById("idiom-answer-submit");
|
||
|
||
if (!input || !feedbackEl || !submitBtn) return;
|
||
|
||
const answer = input.value.trim();
|
||
if (!answer) {
|
||
feedbackEl.textContent = "请输入成语答案";
|
||
feedbackEl.style.color = "#ef4444";
|
||
return;
|
||
}
|
||
|
||
submitBtn.disabled = true;
|
||
submitBtn.textContent = "提交中...";
|
||
|
||
try {
|
||
const response = await fetch("/idiom-quiz/answer", {
|
||
method: "POST",
|
||
headers: {
|
||
"X-CSRF-TOKEN": csrf(),
|
||
"Content-Type": "application/json",
|
||
"Accept": "application/json",
|
||
},
|
||
body: JSON.stringify({
|
||
round_id: currentRoundId,
|
||
answer: answer,
|
||
room_id: currentRoomId,
|
||
}),
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.status === "success") {
|
||
feedbackEl.textContent = data.message || "🎉 回答正确!";
|
||
feedbackEl.style.color = "#16a34a";
|
||
input.disabled = true;
|
||
|
||
// 延迟关闭弹窗
|
||
setTimeout(() => {
|
||
closeIdiomAnswerModal();
|
||
}, 2000);
|
||
} else {
|
||
feedbackEl.textContent = data.message || "答案不正确";
|
||
feedbackEl.style.color = "#ef4444";
|
||
submitBtn.disabled = false;
|
||
submitBtn.textContent = "提交答案";
|
||
input.focus();
|
||
input.select();
|
||
}
|
||
} catch (error) {
|
||
feedbackEl.textContent = "网络错误,请稍后重试";
|
||
feedbackEl.style.color = "#ef4444";
|
||
submitBtn.disabled = false;
|
||
submitBtn.textContent = "提交答案";
|
||
}
|
||
}
|
||
|
||
// ── 事件绑定 ──
|
||
|
||
export function bindIdiomQuizControls() {
|
||
// 已经绑定的不再重复绑定
|
||
if (document.getElementById("idiom-answer-modal")?.dataset?.idiomBound) return;
|
||
const modal = document.getElementById("idiom-answer-modal");
|
||
if (modal) modal.dataset.idiomBound = "1";
|
||
|
||
// 关闭按钮
|
||
document.addEventListener("click", (e) => {
|
||
const closeBtn = e.target.closest("[data-idiom-answer-close]");
|
||
if (closeBtn) {
|
||
closeIdiomAnswerModal();
|
||
return;
|
||
}
|
||
|
||
// 点击遮罩层关闭
|
||
const overlay = e.target.closest("#idiom-answer-modal");
|
||
if (overlay && e.target === overlay) {
|
||
closeIdiomAnswerModal();
|
||
}
|
||
});
|
||
|
||
// 提交按钮
|
||
document.addEventListener("click", (e) => {
|
||
const submitBtn = e.target.closest("[data-idiom-answer-submit]");
|
||
if (submitBtn) {
|
||
e.preventDefault();
|
||
submitIdiomAnswer();
|
||
}
|
||
});
|
||
|
||
// 输入框 Enter 提交
|
||
document.addEventListener("keydown", (e) => {
|
||
const input = e.target.closest("#idiom-answer-input");
|
||
if (input && e.key === "Enter" && !e.shiftKey) {
|
||
e.preventDefault();
|
||
submitIdiomAnswer();
|
||
}
|
||
});
|
||
|
||
// 聊天消息中的【答题】按钮点击
|
||
document.addEventListener("click", (e) => {
|
||
const btn = e.target.closest("[data-idiom-answer-btn]");
|
||
if (!btn) return;
|
||
|
||
// 已答完的按钮不可点击
|
||
if (btn.dataset.idiomAnswered === "1") {
|
||
window.chatToast?.show({
|
||
title: "🧩 猜成语",
|
||
message: "这道题已被答过了,等下一题吧!",
|
||
icon: "😅",
|
||
color: "#9ca3af",
|
||
duration: 3000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
const roundId = parseInt(btn.dataset.idiomAnswerBtn || "0", 10);
|
||
const hint = btn.dataset.idiomHint || "";
|
||
const rewardGold = parseInt(btn.dataset.idiomGold || "0", 10);
|
||
const rewardExp = parseInt(btn.dataset.idiomExp || "0", 10);
|
||
|
||
if (roundId > 0) {
|
||
openIdiomAnswerModal(roundId, hint, rewardGold, rewardExp);
|
||
}
|
||
});
|
||
|
||
// ── 猜成语结果消息中的用户名可点击 → 打开用户名片
|
||
// 注:单击/双击已由 right-panel.js 的全局 [data-chat-message-user] 事件委托统一处理
|
||
|
||
}
|
||
|
||
// ── 挂载到 window ──
|
||
window.openIdiomAnswerModal = openIdiomAnswerModal;
|
||
window.closeIdiomAnswerModal = closeIdiomAnswerModal;
|
||
window.submitIdiomAnswer = submitIdiomAnswer;
|
||
window.handleIdiomGameStarted = handleIdiomGameStarted;
|
||
window.handleIdiomGameAnswered = handleIdiomGameAnswered;
|