const msgTip = document.getElementById('msgTip'); const pwdTip = document.getElementById('pwdTip'); const agreeTip = document.getElementById('agreeTip'); const captchaTip = document.getElementById('captchaTip'); const form = document.getElementById('form'); const usernameInput = document.getElementById('loginUsername'); const passwordInput = document.getElementById('loginPassword'); const captchaInput = document.getElementById('captchaAnswer'); const captchaImg = document.getElementById('captchaImg'); const agreeBox = document.getElementById('agreeBox'); const resetUser = document.getElementById('resetUser'); const registerBtn = document.getElementById('registerBtn'); const loginButton = document.getElementById('loginBtn'); /* ── 图形验证码(gateway 代理 captcha 服务:GET /captcha/image) ── */ let captchaToken = ''; let captchaLoading = false; // 防重复点击:加载中忽略再次触发 async function refreshCaptcha() { if (captchaLoading) return; captchaLoading = true; captchaToken = ''; try { const res = await fetch('/captcha/image', { cache: 'no-store' }); if (!res.ok) throw new Error('captcha load failed'); captchaToken = res.headers.get('X-Captcha-Token') || ''; const blob = await res.blob(); if (captchaImg.src && captchaImg.src.startsWith('blob:')) URL.revokeObjectURL(captchaImg.src); captchaImg.src = URL.createObjectURL(blob); captchaImg.alt = '点击刷新'; } catch (e) { captchaImg.removeAttribute('src'); captchaImg.alt = '加载失败,点击重试'; } finally { captchaLoading = false; } } captchaImg.addEventListener('click', refreshCaptcha); refreshCaptcha(); resetUser.addEventListener('click', function() { clearTipStyle(); }); function clearTipStyle() { msgTip.innerHTML = ''; pwdTip.innerHTML = ''; agreeTip.innerHTML = ''; captchaTip.innerHTML = ''; msgTip.classList.remove('tip-red', 'tip-yellow', 'tip-green'); pwdTip.classList.remove('tip-red', 'tip-yellow', 'tip-green'); agreeTip.classList.remove('tip-red'); captchaTip.classList.remove('tip-red'); } clearTipStyle(); function checkUsername() { const result = FormValidators.username(usernameInput.value); msgTip.textContent = result.message; msgTip.className = result.className; return result.valid ? result.value : false; } function checkPwd() { const result = FormValidators.password(passwordInput.value); pwdTip.textContent = result.message; pwdTip.className = result.className; return result.valid ? result.value : false; } function checkCaptcha() { captchaTip.innerHTML = ''; captchaTip.classList.remove('tip-red'); const v = captchaInput.value.trim(); if (!v) { captchaTip.innerHTML = '请输入验证码!'; captchaTip.classList.add('tip-red'); return false; } if (!captchaToken) { captchaTip.innerHTML = '验证码未加载,请点击图片刷新'; captchaTip.classList.add('tip-red'); return false; } return v; } function checkAgree() { agreeTip.innerHTML = ''; agreeTip.classList.remove('tip-red'); if (!agreeBox.checked) { agreeTip.innerHTML = '请同意用户协议!'; agreeTip.classList.add('tip-red'); return false; } return true; } usernameInput.addEventListener('focus', checkUsername); passwordInput.addEventListener('focus', checkPwd); usernameInput.addEventListener('input', checkUsername); passwordInput.addEventListener('input', checkPwd); usernameInput.addEventListener('blur', checkUsername); passwordInput.addEventListener('blur', checkPwd); agreeBox.addEventListener('change', checkAgree); registerBtn.addEventListener('click', function() { location.href = 'register.html'; }); form.addEventListener('submit', async function(e) { e.preventDefault(); clearTipStyle(); const userOk = checkUsername(); const pwdOk = checkPwd(); const captchaOk = checkCaptcha(); const agreeOk = checkAgree(); if (!userOk || !pwdOk || !captchaOk || !agreeOk) return; const jsonBody = JSON.stringify({ username: userOk, password: pwdOk, captcha_token: captchaToken, captcha_answer: captchaOk }); try { loginButton.disabled = true; const res = await fetch('/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: jsonBody }); const responseText = await res.text(); let result; try { result = JSON.parse(responseText); } catch { throw new Error('服务器响应格式异常'); } if (!res.ok) throw new Error(result.message || '登录失败'); if (result.success) { // Token 已由网关通过 HttpOnly Cookie 下发,JS 不再经手 alert('登录成功'); location.href = '/dnfs.html'; } else { alert(result.message || '登录失败'); } } catch (err) { alert(err.message || '接口请求失败'); } finally { // 无论成败都刷新验证码:Token 已被一次性消费,或需防重试 captchaInput.value = ''; refreshCaptcha(); loginButton.disabled = false; } });