89 lines
No EOL
3.5 KiB
JavaScript
89 lines
No EOL
3.5 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
||
|
||
const DOMElements = {
|
||
loginForm: document.getElementById('login-form'),
|
||
toastContainer: document.getElementById('toast-container'),
|
||
};
|
||
const loginButton = DOMElements.loginForm.querySelector('button[type="submit"]');
|
||
const LOGIN_API_URL = '/v0/api/auth/login';
|
||
|
||
const theme = {
|
||
init: () => {
|
||
const storedTheme = localStorage.getItem('theme');
|
||
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||
const currentTheme = storedTheme || (systemPrefersDark ? 'dark' : 'light');
|
||
document.documentElement.dataset.theme = currentTheme;
|
||
}
|
||
};
|
||
|
||
const toast = {
|
||
show: (message, type = 'info', duration = 3000) => {
|
||
const icons = { success: 'fa-check-circle', error: 'fa-times-circle', info: 'fa-info-circle' };
|
||
const iconClass = icons[type] || 'fa-info-circle';
|
||
const toastElement = document.createElement('div');
|
||
toastElement.className = `toast ${type}`;
|
||
toastElement.innerHTML = `<i class="toast-icon fa-solid ${iconClass}"></i><p class="toast-message">${message}</p><button class="toast-close" data-toast-close>×</button>`;
|
||
DOMElements.toastContainer.appendChild(toastElement);
|
||
requestAnimationFrame(() => toastElement.classList.add('show'));
|
||
const timeoutId = setTimeout(() => hideToast(toastElement), duration);
|
||
toastElement.querySelector('[data-toast-close]').addEventListener('click', () => {
|
||
clearTimeout(timeoutId);
|
||
hideToast(toastElement);
|
||
});
|
||
}
|
||
};
|
||
function hideToast(toastElement) {
|
||
if (!toastElement) return;
|
||
toastElement.classList.remove('show');
|
||
toastElement.addEventListener('transitionend', () => toastElement.remove(), { once: true });
|
||
}
|
||
|
||
async function handleLogin(e) {
|
||
e.preventDefault();
|
||
|
||
// 获取并确认值
|
||
const username = DOMElements.loginForm.username.value.trim();
|
||
const password = DOMElements.loginForm.password.value.trim();
|
||
|
||
if (username === '') {
|
||
toast.show('用户名不能为空', 'error');
|
||
DOMElements.loginForm.username.focus();
|
||
return;
|
||
}
|
||
|
||
if (password === '') {
|
||
toast.show('密码不能为空', 'error');
|
||
DOMElements.loginForm.password.focus();
|
||
return;
|
||
}
|
||
|
||
loginButton.disabled = true;
|
||
loginButton.querySelector('span').textContent = '登录中...';
|
||
|
||
try {
|
||
const response = await fetch(LOGIN_API_URL, {
|
||
method: 'POST',
|
||
body: new URLSearchParams(new FormData(DOMElements.loginForm))
|
||
});
|
||
const result = await response.json();
|
||
if (response.ok) {
|
||
toast.show('登录成功,正在跳转...', 'success');
|
||
setTimeout(() => { window.location.href = '/'; }, 500);
|
||
} else {
|
||
throw new Error(result.error || `登录失败: ${response.status}`);
|
||
}
|
||
} catch (error) {
|
||
toast.show(error.message, 'error');
|
||
loginButton.disabled = false;
|
||
loginButton.querySelector('span').textContent = '登录';
|
||
}
|
||
}
|
||
|
||
function init() {
|
||
theme.init();
|
||
if (DOMElements.loginForm) {
|
||
DOMElements.loginForm.addEventListener('submit', handleLogin);
|
||
}
|
||
}
|
||
init();
|
||
}); |