(function () { var userConfig = window.VISITOR_LOGIN_CONFIG || {}; var config = Object.assign({ frontendMode: "cluster", deploymentMode: "cluster", defaultServerIp: "", apiBaseUrl: "http://localhost:9098", deploymentConfigPath: "/api/deployment/config", defaultBackendPort: "9098", loginPath: "/api/login", captchaPath: "/captchaImage", title: "访客机自助登记\n管理平台" }, userConfig); config.frontendMode = normalizeDeploymentMode(userConfig.frontendMode || userConfig.deploymentMode || config.frontendMode); config.deploymentMode = normalizeDeploymentMode(config.deploymentMode); config.requireServerIp = typeof userConfig.requireServerIp === "boolean" ? userConfig.requireServerIp : config.frontendMode === "cluster"; var loginCard = document.querySelector(".login-card"); var title = document.getElementById("appTitle"); var serverIpGroup = document.getElementById("serverIpGroup"); var serverIp = document.getElementById("serverIp"); var username = document.getElementById("username"); var password = document.getElementById("password"); var captcha = document.getElementById("captcha"); var captchaBox = document.getElementById("captchaBox"); var captchaText = document.getElementById("captchaText"); var captchaImage = document.getElementById("captchaImage"); var form = document.getElementById("loginForm"); var message = document.getElementById("formMessage"); var captchaUuid = ""; var captchaRequired = true; document.title = String(config.title || "").replace(/\n/g, ""); title.innerHTML = String(config.title || "").replace(/\n/g, "
"); serverIp.value = config.defaultServerIp || ""; applyLoginMode(); loadBackendDeploymentConfig(); loadCaptchaIfReady(); captchaBox.addEventListener("click", function () { loadCaptcha(); }); serverIp.addEventListener("blur", function () { if (config.requireServerIp && isValidIpOrHost(serverIp.value.trim())) { loadCaptcha(); } }); form.addEventListener("submit", function (event) { event.preventDefault(); setMessage("", ""); var payload = { username: username.value.trim(), password: password.value, code: captcha.value.trim(), uuid: captchaUuid }; if (config.requireServerIp) { payload.serverIp = serverIp.value.trim(); } var error = validate(payload); if (error) { setMessage(error, "error"); return; } submitLogin(payload); }); function validate(payload) { if (config.requireServerIp && !isValidIpOrHost(payload.serverIp)) { return "请输入正确的IP地址"; } if (!payload.username) { return "请输入用户名"; } if (!payload.password) { return "请输入密码"; } if (captchaRequired && !captchaUuid) { return "请先获取验证码"; } if (captchaRequired && !payload.code) { return "请输入验证码"; } return ""; } function applyLoginMode() { serverIpGroup.hidden = !config.requireServerIp; loginCard.classList.toggle("no-server-ip", !config.requireServerIp); localStorage.setItem("visitor_admin_frontend_mode", config.frontendMode); localStorage.setItem("visitor_admin_require_server_ip", String(config.requireServerIp)); } function loadCaptchaIfReady() { if (!config.requireServerIp || serverIp.value.trim()) { loadCaptcha(); } } function loadBackendDeploymentConfig() { if (!config.deploymentConfigPath) { return; } fetch(getConfiguredApiBaseUrl() + normalizePath(config.deploymentConfigPath), { method: "GET" }).then(function (response) { if (!response.ok) { throw new Error("部署配置加载失败"); } return response.json(); }).then(function (result) { var data = result.data || {}; if (result.code !== 200 || !data) { return; } if (data.deploymentMode) { config.backendDeploymentMode = normalizeDeploymentMode(data.deploymentMode); } config.middlePlatformEnabled = data.middlePlatformEnabled === true; localStorage.setItem("visitor_admin_backend_deployment_mode", config.backendDeploymentMode || ""); localStorage.setItem("visitor_admin_middle_platform_enabled", String(config.middlePlatformEnabled)); applyLoginMode(); loadCaptchaIfReady(); }).catch(function () { applyLoginMode(); }); } function isValidIpOrHost(value) { if (!value) { return false; } value = value.replace(/^https?:\/\//i, ""); var ipPattern = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}(:\d{1,5})?$/; var hostPattern = /^[a-zA-Z0-9.-]+(:\d{1,5})?$/; return ipPattern.test(value) || hostPattern.test(value); } function loadCaptcha() { var baseUrl; try { baseUrl = getApiBaseUrl(); } catch (error) { captchaText.textContent = "随机验证码区"; captchaImage.hidden = true; captchaText.hidden = false; return; } captchaText.textContent = "加载中"; captchaText.hidden = false; captchaImage.hidden = true; fetch(baseUrl + normalizePath(config.captchaPath), { method: "GET" }).then(function (response) { if (!response.ok) { throw new Error("验证码加载失败"); } return response.json(); }).then(function (result) { if (result.code !== 200) { throw new Error(result.msg || "验证码加载失败"); } captcha.value = ""; captchaUuid = result.uuid || ""; if (result.captchaEnabled === false) { captchaRequired = false; captchaText.textContent = "无需验证码"; return; } captchaRequired = true; if (!result.img) { throw new Error("验证码图片为空"); } captchaImage.src = "data:image/jpeg;base64," + result.img; captchaImage.hidden = false; captchaText.hidden = true; }).catch(function (error) { captchaUuid = ""; captchaRequired = true; captchaText.textContent = "点击重试"; captchaText.hidden = false; captchaImage.hidden = true; setMessage(error.message || "验证码加载失败", "error"); }); } function submitLogin(payload) { setMessage("登录中...", ""); fetch(getApiBaseUrl() + normalizePath(config.loginPath), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function (response) { return response.json(); }).then(function (result) { if (result.code !== 200) { throw new Error(result.msg || "登录失败"); } if (result.token) { localStorage.setItem("visitor_admin_token", result.token); } localStorage.setItem("visitor_admin_api_base", getApiBaseUrl()); localStorage.setItem("visitor_admin_login_result", JSON.stringify(result)); setMessage("登录成功", "success"); window.setTimeout(function () { window.location.href = "./pages/dashboard.html"; }, 300); }).catch(function (error) { setMessage(error.message || "登录失败", "error"); loadCaptcha(); }); } function setMessage(text, type) { message.textContent = text; message.classList.toggle("success", type === "success"); if (!text || !window.AppMessage) { return; } if (type === "success") { AppMessage.success("操作成功"); } else if (type === "error") { AppMessage.error("操作失败:" + text); } } function getApiBaseUrl() { if (!config.requireServerIp) { return getConfiguredApiBaseUrl(); } return normalizeServerIp(serverIp.value.trim()); } function getConfiguredApiBaseUrl() { return trimRightSlash(config.apiBaseUrl || window.location.origin); } function normalizeServerIp(value) { if (!isValidIpOrHost(value)) { throw new Error("请输入正确的IP地址"); } var result = value; if (!/^https?:\/\//i.test(result)) { result = "http://" + result; } var url = new URL(result); if (!url.port && config.defaultBackendPort) { url.port = config.defaultBackendPort; } return trimRightSlash(url.origin); } function normalizePath(path) { return "/" + String(path || "").replace(/^\/+/, ""); } function trimRightSlash(value) { return String(value || "").replace(/\/+$/, ""); } function normalizeDeploymentMode(value) { return String(value || "").toLowerCase() === "cluster" ? "cluster" : "standalone"; } })();