343 lines
9.9 KiB
JavaScript
343 lines
9.9 KiB
JavaScript
/**
|
|
* 云酒馆 - 用户认证模块
|
|
* 处理用户登录和注册功能
|
|
*/
|
|
|
|
// ===== 配置 =====
|
|
const CONFIG = {
|
|
API_BASE_URL: 'http://localhost:8888/app',
|
|
TOKEN_KEY: 'st_access_token',
|
|
REFRESH_TOKEN_KEY: 'st_refresh_token',
|
|
USER_KEY: 'st_user_info',
|
|
};
|
|
|
|
// ===== DOM 元素 =====
|
|
const elements = {
|
|
tabs: document.querySelectorAll('.auth-tab'),
|
|
loginForm: document.getElementById('loginForm'),
|
|
registerForm: document.getElementById('registerForm'),
|
|
messageBox: document.getElementById('messageBox'),
|
|
loadingOverlay: document.getElementById('loadingOverlay'),
|
|
passwordToggles: document.querySelectorAll('.password-toggle'),
|
|
};
|
|
|
|
// ===== 初始化 =====
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initTabs();
|
|
initForms();
|
|
initPasswordToggles();
|
|
checkAutoLogin();
|
|
});
|
|
|
|
// ===== 标签页切换 =====
|
|
function initTabs() {
|
|
elements.tabs.forEach(tab => {
|
|
tab.addEventListener('click', () => {
|
|
const tabName = tab.dataset.tab;
|
|
switchTab(tabName);
|
|
});
|
|
});
|
|
}
|
|
|
|
function switchTab(tabName) {
|
|
// 更新标签页状态
|
|
elements.tabs.forEach(tab => {
|
|
tab.classList.toggle('active', tab.dataset.tab === tabName);
|
|
});
|
|
|
|
// 更新表单显示
|
|
elements.loginForm.classList.toggle('active', tabName === 'login');
|
|
elements.registerForm.classList.toggle('active', tabName === 'register');
|
|
|
|
// 清空消息
|
|
hideMessage();
|
|
}
|
|
|
|
// ===== 表单初始化 =====
|
|
function initForms() {
|
|
// 登录表单
|
|
elements.loginForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
await handleLogin();
|
|
});
|
|
|
|
// 注册表单
|
|
elements.registerForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
await handleRegister();
|
|
});
|
|
}
|
|
|
|
// ===== 密码显示/隐藏切换 =====
|
|
function initPasswordToggles() {
|
|
elements.passwordToggles.forEach(toggle => {
|
|
toggle.addEventListener('click', () => {
|
|
const targetId = toggle.dataset.target;
|
|
const input = document.getElementById(targetId);
|
|
const icon = toggle.querySelector('i');
|
|
|
|
if (input.type === 'password') {
|
|
input.type = 'text';
|
|
icon.classList.remove('fa-eye');
|
|
icon.classList.add('fa-eye-slash');
|
|
} else {
|
|
input.type = 'password';
|
|
icon.classList.remove('fa-eye-slash');
|
|
icon.classList.add('fa-eye');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ===== 登录处理 =====
|
|
async function handleLogin() {
|
|
const username = document.getElementById('loginUsername').value.trim();
|
|
const password = document.getElementById('loginPassword').value;
|
|
const rememberMe = document.getElementById('rememberMe').checked;
|
|
|
|
// 验证输入
|
|
if (!username || !password) {
|
|
showMessage('请填写完整的登录信息', 'error');
|
|
return;
|
|
}
|
|
|
|
showLoading();
|
|
|
|
try {
|
|
const response = await fetch(`${CONFIG.API_BASE_URL}/auth/login`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ username, password }),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.code === 0) {
|
|
// 登录成功
|
|
saveLoginData(data.data, rememberMe);
|
|
showMessage('登录成功!正在跳转...', 'success');
|
|
|
|
// 延迟跳转到主页
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 1500);
|
|
} else {
|
|
// 登录失败
|
|
showMessage(data.msg || '登录失败,请检查用户名和密码', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('登录错误:', error);
|
|
showMessage('网络错误,请检查服务器连接', 'error');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// ===== 注册处理 =====
|
|
async function handleRegister() {
|
|
const username = document.getElementById('registerUsername').value.trim();
|
|
const password = document.getElementById('registerPassword').value;
|
|
const passwordConfirm = document.getElementById('registerPasswordConfirm').value;
|
|
const nickName = document.getElementById('registerNickname').value.trim();
|
|
const email = document.getElementById('registerEmail').value.trim();
|
|
|
|
// 验证输入
|
|
if (!username || !password || !passwordConfirm) {
|
|
showMessage('请填写必填信息', 'error');
|
|
return;
|
|
}
|
|
|
|
if (username.length < 3 || username.length > 32) {
|
|
showMessage('用户名长度应为 3-32 个字符', 'error');
|
|
return;
|
|
}
|
|
|
|
if (password.length < 6 || password.length > 32) {
|
|
showMessage('密码长度应为 6-32 个字符', 'error');
|
|
return;
|
|
}
|
|
|
|
if (password !== passwordConfirm) {
|
|
showMessage('两次输入的密码不一致', 'error');
|
|
return;
|
|
}
|
|
|
|
// 验证用户名格式
|
|
if (!/^[a-zA-Z0-9_]+$/.test(username)) {
|
|
showMessage('用户名只能包含字母、数字和下划线', 'error');
|
|
return;
|
|
}
|
|
|
|
showLoading();
|
|
|
|
try {
|
|
const requestBody = {
|
|
username,
|
|
password,
|
|
nickName: nickName || username, // 如果没有昵称,使用用户名
|
|
};
|
|
|
|
// 如果填写了邮箱,添加到请求中
|
|
if (email) {
|
|
requestBody.email = email;
|
|
}
|
|
|
|
const response = await fetch(`${CONFIG.API_BASE_URL}/auth/register`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(requestBody),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.code === 0) {
|
|
// 注册成功
|
|
showMessage('注册成功!请登录', 'success');
|
|
|
|
// 清空注册表单
|
|
elements.registerForm.reset();
|
|
|
|
// 切换到登录标签页,并填充用户名
|
|
setTimeout(() => {
|
|
switchTab('login');
|
|
document.getElementById('loginUsername').value = username;
|
|
document.getElementById('loginPassword').focus();
|
|
}, 1500);
|
|
} else {
|
|
// 注册失败
|
|
showMessage(data.msg || '注册失败,请稍后重试', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('注册错误:', error);
|
|
showMessage('网络错误,请检查服务器连接', 'error');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// ===== 保存登录数据 =====
|
|
function saveLoginData(loginData, rememberMe) {
|
|
const { token, refreshToken, user } = loginData;
|
|
|
|
// 保存到 localStorage 或 sessionStorage
|
|
const storage = rememberMe ? localStorage : sessionStorage;
|
|
|
|
storage.setItem(CONFIG.TOKEN_KEY, token);
|
|
storage.setItem(CONFIG.REFRESH_TOKEN_KEY, refreshToken);
|
|
storage.setItem(CONFIG.USER_KEY, JSON.stringify(user));
|
|
}
|
|
|
|
// ===== 自动登录检查 =====
|
|
function checkAutoLogin() {
|
|
// 检查是否已经登录
|
|
const token = localStorage.getItem(CONFIG.TOKEN_KEY) ||
|
|
sessionStorage.getItem(CONFIG.TOKEN_KEY);
|
|
|
|
if (token) {
|
|
// 已登录,尝试验证 token 是否有效
|
|
verifyToken(token);
|
|
}
|
|
}
|
|
|
|
// ===== 验证 Token =====
|
|
async function verifyToken(token) {
|
|
try {
|
|
const response = await fetch(`${CONFIG.API_BASE_URL}/auth/userinfo`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'x-token': token,
|
|
},
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
if (data.code === 0) {
|
|
// Token 有效,直接跳转到主页
|
|
showMessage('检测到已登录,正在跳转...', 'success');
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 1000);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Token 验证失败:', error);
|
|
// Token 无效,清除存储
|
|
clearLoginData();
|
|
}
|
|
}
|
|
|
|
// ===== 清除登录数据 =====
|
|
function clearLoginData() {
|
|
localStorage.removeItem(CONFIG.TOKEN_KEY);
|
|
localStorage.removeItem(CONFIG.REFRESH_TOKEN_KEY);
|
|
localStorage.removeItem(CONFIG.USER_KEY);
|
|
sessionStorage.removeItem(CONFIG.TOKEN_KEY);
|
|
sessionStorage.removeItem(CONFIG.REFRESH_TOKEN_KEY);
|
|
sessionStorage.removeItem(CONFIG.USER_KEY);
|
|
}
|
|
|
|
// ===== 消息提示 =====
|
|
function showMessage(message, type = 'error') {
|
|
elements.messageBox.textContent = message;
|
|
elements.messageBox.className = `message-box show ${type}`;
|
|
|
|
// 3秒后自动隐藏
|
|
setTimeout(() => {
|
|
hideMessage();
|
|
}, 5000);
|
|
}
|
|
|
|
function hideMessage() {
|
|
elements.messageBox.classList.remove('show');
|
|
}
|
|
|
|
// ===== 加载动画 =====
|
|
function showLoading() {
|
|
elements.loadingOverlay.classList.add('show');
|
|
}
|
|
|
|
function hideLoading() {
|
|
elements.loadingOverlay.classList.remove('show');
|
|
}
|
|
|
|
// ===== 工具函数:获取当前登录用户 =====
|
|
export function getCurrentUser() {
|
|
const userJson = localStorage.getItem(CONFIG.USER_KEY) ||
|
|
sessionStorage.getItem(CONFIG.USER_KEY);
|
|
return userJson ? JSON.parse(userJson) : null;
|
|
}
|
|
|
|
// ===== 工具函数:获取 Token =====
|
|
export function getToken() {
|
|
return localStorage.getItem(CONFIG.TOKEN_KEY) ||
|
|
sessionStorage.getItem(CONFIG.TOKEN_KEY);
|
|
}
|
|
|
|
// ===== 工具函数:登出 =====
|
|
export async function logout() {
|
|
const token = getToken();
|
|
|
|
if (token) {
|
|
try {
|
|
await fetch(`${CONFIG.API_BASE_URL}/auth/logout`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'x-token': token,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error('登出请求失败:', error);
|
|
}
|
|
}
|
|
|
|
clearLoginData();
|
|
window.location.href = '/auth.html';
|
|
}
|
|
|
|
// ===== 导出配置供其他模块使用 =====
|
|
export { CONFIG };
|