迁移首页登录脚本
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
// 首页登录交互入口,负责验证码刷新、房间提示、性别选中态和 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<void>}
|
||||
*/
|
||||
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();
|
||||
Reference in New Issue
Block a user