ai_v/static/js/auth.js

203 lines
6.8 KiB
JavaScript

/**
* Auth Modes:
* 0 - Login
* 1 - Register
* 2 - Reset Password
*/
let authMode = 0;
const getEl = (id) => document.getElementById(id);
const updateUI = () => {
const title = getEl('authTitle');
const sub = getEl('authSub');
const submitBtnSpan = getEl('authSubmitBtn')?.querySelector('span');
const switchBtn = getEl('authSwitchBtn');
const forgotBtn = getEl('forgotPwdBtn');
const smsGroup = getEl('smsGroup');
const captchaGroup = getEl('captchaGroup');
if (!title || !sub || !submitBtnSpan || !switchBtn || !forgotBtn || !smsGroup || !captchaGroup) return;
if (authMode === 1) { // Register
title.innerText = "加入视界 AI";
sub.innerText = "注册并开启创作";
submitBtnSpan.innerText = "立即注册";
switchBtn.innerText = "已有账号?返回登录";
forgotBtn.classList.add('hidden');
smsGroup.classList.remove('hidden');
captchaGroup.classList.remove('hidden'); // 注册模式默认显示图形验证码防止刷短信
} else if (authMode === 2) { // Reset Password
title.innerText = "重置密码";
sub.innerText = "验证短信以设置新密码";
submitBtnSpan.innerText = "确认重置";
switchBtn.innerText = "我想起来了,返回登录";
forgotBtn.classList.add('hidden');
smsGroup.classList.remove('hidden');
captchaGroup.classList.remove('hidden'); // 重置模式默认显示
} else { // Login
title.innerText = "欢迎回来";
sub.innerText = "请登录以开启 AI 创作之旅";
submitBtnSpan.innerText = "立即登录";
switchBtn.innerText = "没有账号?立即注册";
forgotBtn.classList.remove('hidden');
smsGroup.classList.add('hidden');
captchaGroup.classList.add('hidden'); // 登录默认隐藏,除非高频失败
}
};
const refreshCaptcha = () => {
const phone = getEl('authPhone')?.value;
const captchaImg = getEl('captchaImg');
if (!phone || !captchaImg) return;
captchaImg.src = `/api/auth/captcha?phone=${phone}&t=${Date.now()}`;
};
const handleAuth = async () => {
const phone = getEl('authPhone')?.value;
const password = getEl('authPass')?.value;
if (!phone || !password) {
return showToast('请输入手机号和密码', 'warning');
}
let url = '';
let body = { phone, password };
if (authMode === 1) {
url = '/api/auth/register';
body.code = getEl('authCode')?.value;
} else if (authMode === 0) {
url = '/api/auth/login';
if (!getEl('captchaGroup')?.classList.contains('hidden')) {
body.code = getEl('authCaptcha')?.value;
}
} else if (authMode === 2) {
url = '/api/auth/reset_password';
body.code = getEl('authCode')?.value;
if (!body.code) return showToast('请输入短信验证码', 'warning');
}
try {
const btn = getEl('authSubmitBtn');
if (btn) btn.disabled = true;
const r = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const d = await r.json();
if (r.status === 403 && d.require_captcha) {
showToast(d.error, 'warning');
getEl('captchaGroup')?.classList.remove('hidden');
refreshCaptcha();
if (btn) btn.disabled = false;
return;
}
if (d.error) {
showToast(d.error, 'error');
if (getEl('captchaGroup') && !getEl('captchaGroup').classList.contains('hidden')) {
refreshCaptcha();
}
if (btn) btn.disabled = false;
} else {
showToast(d.message, 'success');
if (authMode === 1 || authMode === 2) {
authMode = 0;
updateUI();
if (btn) btn.disabled = false;
} else {
const urlParams = new URLSearchParams(window.location.search);
const nextUrl = urlParams.get('next') || '/';
window.location.href = nextUrl;
}
}
} catch (e) {
showToast('网络连接失败', 'error');
const btn = getEl('authSubmitBtn');
if (btn) btn.disabled = false;
}
};
// 初始化
document.addEventListener('DOMContentLoaded', () => {
updateUI();
getEl('authSwitchBtn').onclick = () => {
authMode = (authMode === 0) ? 1 : 0;
updateUI();
if (authMode === 1 || authMode === 2) refreshCaptcha();
};
getEl('forgotPwdBtn').onclick = () => {
authMode = 2;
updateUI();
refreshCaptcha();
};
getEl('captchaImg').onclick = refreshCaptcha;
getEl('authSubmitBtn').onclick = handleAuth;
// 回车登录支持
['authPhone', 'authPass', 'authCode', 'authCaptcha'].forEach(id => {
getEl(id)?.addEventListener('keydown', (e) => {
if (e.key === 'Enter') handleAuth();
});
});
getEl('sendSmsBtn').onclick = async () => {
const phone = getEl('authPhone')?.value;
const captcha = getEl('authCaptcha')?.value;
const btn = getEl('sendSmsBtn');
if (!phone) return showToast('请输入手机号', 'warning');
if (!captcha) {
getEl('captchaGroup')?.classList.remove('hidden');
refreshCaptcha();
return showToast('请先输入图形验证码以发送短信', 'warning');
}
btn.disabled = true;
const originalText = btn.innerText;
try {
const r = await fetch('/api/auth/send_code', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone, captcha })
});
const d = await r.json();
if (d.error) {
showToast(d.error, 'error');
btn.disabled = false;
if (d.show_captcha || d.refresh_captcha) {
getEl('captchaGroup')?.classList.remove('hidden');
refreshCaptcha();
}
} else {
showToast(d.message, 'success');
// 发送成功后也要刷新图形验证码,防止被再次利用
refreshCaptcha();
let countdown = 60;
const timer = setInterval(() => {
btn.innerText = `${countdown}秒后重试`;
countdown--;
if (countdown < 0) {
clearInterval(timer);
btn.innerText = originalText;
btn.disabled = false;
}
}, 1000);
}
} catch (e) {
showToast('短信发送失败', 'error');
btn.disabled = false;
}
};
});