// 首页登录交互入口,负责验证码刷新、房间提示、性别选中态和 AJAX 登录。 let homeLoginControlsBound = false; /** * 读取 CSRF 令牌,供登录请求使用。 * * @returns {string} */ function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") ?? ""; } /** * 刷新验证码图片,避免浏览器缓存旧图。 * * @param {HTMLImageElement} captchaImage * @returns {void} */ function refreshCaptcha(captchaImage) { const refreshUrl = captchaImage.getAttribute("data-captcha-refresh-url") ?? "/captcha/default"; captchaImage.src = `${refreshUrl}?${Math.random()}`; } /** * 同步性别单选项的选中视觉状态。 * * @returns {void} */ function syncSelectedState() { document.querySelectorAll(".gender-option").forEach((option) => { const input = option.querySelector('input[type="radio"]'); option.classList.toggle("selected", Boolean(input?.checked)); }); } /** * 根据当前房间选择更新提示文案。 * * @returns {void} */ function updateRoomHint() { const roomSelect = document.getElementById("room_id"); const hint = document.getElementById("room-hint"); if (!roomSelect || !hint || roomSelect.selectedIndex < 0) { return; } const selectedOption = roomSelect.options[roomSelect.selectedIndex]; const roomName = selectedOption.getAttribute("data-room-name") || selectedOption.text; const roomOwner = selectedOption.getAttribute("data-room-owner") || "未设置"; hint.textContent = `当前房间:${roomName} / 房主:${roomOwner}`; } /** * 展示或隐藏登录提示框。 * * @param {string} message * @param {string} type * @param {boolean} visible * @returns {void} */ function showAlert(message, type, visible) { const alertBox = document.getElementById("alert-box"); if (!alertBox) { return; } alertBox.textContent = message; alertBox.className = type === "success" ? "alert-success" : "alert-error"; alertBox.id = "alert-box"; alertBox.style.display = visible ? "block" : "none"; } /** * 打开聊天室窗口,并尽量铺满当前可用屏幕。 * * @param {string} url * @returns {void} */ function openChatRoomWindow(url) { const chatWindow = window.open( url, "chatroom", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes", ); if (!chatWindow) { return; } chatWindow.moveTo(0, 0); chatWindow.resizeTo(window.screen.availWidth, window.screen.availHeight); chatWindow.focus(); } /** * 处理登录表单提交。 * * @param {SubmitEvent} event * @returns {Promise} */ async function submitLogin(event) { event.preventDefault(); const form = event.target; if (!(form instanceof HTMLFormElement)) { return; } const button = document.getElementById("submit-btn"); const captchaInput = document.getElementById("captcha"); const captchaImage = document.getElementById("captcha-img"); const loginUrl = form.getAttribute("data-login-url") ?? form.action; const roomsUrl = form.getAttribute("data-rooms-url") ?? "/rooms"; const roomUrlTemplate = form.getAttribute("data-room-url-template") ?? "/room/:id"; const formData = new FormData(form); const data = Object.fromEntries(formData.entries()); const roomId = data.room_id || "1"; if (button instanceof HTMLButtonElement) { button.disabled = true; button.innerText = "正在进入..."; } showAlert("", "error", false); try { const response = await fetch(loginUrl, { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", "X-CSRF-TOKEN": getCsrfToken(), Accept: "application/json", }, body: JSON.stringify(data), }); const body = await response.json(); if (response.status === 419 || body?.message === "CSRF token mismatch.") { showAlert("安全令牌已过期,正在刷新页面...", "error", true); window.setTimeout(() => { window.location.reload(); }, 1500); return; } if (response.status === 200 && body.status === "success") { showAlert(body.message, "success", true); openChatRoomWindow(roomUrlTemplate.replace(":id", roomId)); window.setTimeout(() => { window.location.href = roomsUrl; }, 1500); return; } const errorMessage = body.message || (body.errors ? Object.values(body.errors)[0][0] : "登录失败,请稍后再试。"); showAlert(errorMessage, "error", true); if (captchaImage instanceof HTMLImageElement) { refreshCaptcha(captchaImage); } if (captchaInput instanceof HTMLInputElement) { captchaInput.value = ""; } if (button instanceof HTMLButtonElement) { button.disabled = false; button.innerText = "进入和平聊吧"; } } catch { showAlert("网络或服务器异常,请稍后再试。", "error", true); if (captchaImage instanceof HTMLImageElement) { refreshCaptcha(captchaImage); } if (button instanceof HTMLButtonElement) { button.disabled = false; button.innerText = "进入和平聊吧"; } } } /** * 绑定首页登录页交互。 * * @returns {void} */ function bindHomeLoginControls() { if (homeLoginControlsBound || typeof document === "undefined") { return; } homeLoginControlsBound = true; document.addEventListener("click", (event) => { if (!(event.target instanceof HTMLImageElement)) { return; } if (event.target.hasAttribute("data-captcha-refresh-url")) { refreshCaptcha(event.target); } }); document.querySelectorAll('.gender-option input[type="radio"]').forEach((input) => { input.addEventListener("change", syncSelectedState); }); document.getElementById("room_id")?.addEventListener("change", updateRoomHint); document.getElementById("login-form")?.addEventListener("submit", (event) => { void submitLogin(event); }); syncSelectedState(); updateRoomHint(); } bindHomeLoginControls();