150 lines
No EOL
5.7 KiB
JavaScript
150 lines
No EOL
5.7 KiB
JavaScript
// js/init.js
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const DOMElements = {
|
||
initForm: document.getElementById('init-form'),
|
||
initButton: null,
|
||
toastContainer: document.getElementById('toast-container'),
|
||
usernameInput: document.getElementById('username'),
|
||
passwordInput: document.getElementById('password'),
|
||
confirmPasswordInput: document.getElementById('confirm_password'),
|
||
};
|
||
|
||
const INIT_API_URL = '/v0/api/auth/init';
|
||
const PASSWORD_MIN_LENGTH = 8;
|
||
const TOAST_DEFAULT_DURATION = 3000;
|
||
const REDIRECT_DELAY_SUCCESS = 1500;
|
||
|
||
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 = {
|
||
_container: null,
|
||
_icons: { success: 'fa-check-circle', error: 'fa-times-circle', info: 'fa-info-circle' },
|
||
|
||
init: (containerElement) => {
|
||
if (!containerElement) {
|
||
console.error('Toast container element not found.');
|
||
return;
|
||
}
|
||
toast._container = containerElement;
|
||
toast._container.addEventListener('click', (e) => {
|
||
if (e.target.dataset.toastClose !== undefined) {
|
||
toast._hideToast(e.target.closest('.toast'));
|
||
}
|
||
});
|
||
},
|
||
|
||
show: (message, type = 'info', duration = TOAST_DEFAULT_DURATION) => {
|
||
if (!toast._container) {
|
||
console.error('Toast module not initialized. Container is missing.');
|
||
return;
|
||
}
|
||
|
||
const iconClass = toast._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>
|
||
`;
|
||
toast._container.appendChild(toastElement);
|
||
requestAnimationFrame(() => toastElement.classList.add('show'));
|
||
setTimeout(() => toast._hideToast(toastElement), duration);
|
||
},
|
||
|
||
_hideToast: (toastElement) => {
|
||
if (!toastElement) return;
|
||
toastElement.classList.remove('show');
|
||
toastElement.addEventListener('transitionend', () => toastElement.remove(), { once: true });
|
||
}
|
||
};
|
||
|
||
async function handleInitSubmit(e) {
|
||
e.preventDefault();
|
||
|
||
// 1. 获取并修剪输入值
|
||
const username = DOMElements.usernameInput.value.trim(); // 获取用户名并去除前后空格
|
||
const password = DOMElements.passwordInput.value.trim();
|
||
const confirmPassword = DOMElements.confirmPasswordInput.value.trim();
|
||
|
||
// 2. 添加用户名输入框的空值验证
|
||
if (username === '') {
|
||
toast.show('管理员用户名不能为空', 'error');
|
||
DOMElements.usernameInput.focus();
|
||
return;
|
||
}
|
||
// 其他密码验证逻辑不变
|
||
if (password === '') {
|
||
toast.show('密码不能为空', 'error');
|
||
DOMElements.passwordInput.focus();
|
||
return;
|
||
}
|
||
if (confirmPassword === '') {
|
||
toast.show('确认密码不能为空', 'error');
|
||
DOMElements.confirmPasswordInput.focus();
|
||
return;
|
||
}
|
||
|
||
if (password !== confirmPassword) {
|
||
toast.show('两次输入的密码不匹配', 'error');
|
||
DOMElements.passwordInput.focus();
|
||
return;
|
||
}
|
||
if (password.length < PASSWORD_MIN_LENGTH) {
|
||
toast.show(`密码长度至少为 ${PASSWORD_MIN_LENGTH} 位`, 'error');
|
||
DOMElements.passwordInput.focus();
|
||
return;
|
||
}
|
||
|
||
DOMElements.initButton.disabled = true;
|
||
DOMElements.initButton.querySelector('span').textContent = '设置中...';
|
||
|
||
try {
|
||
const formData = new FormData(DOMElements.initForm);
|
||
formData.set('username', username); // 确保发送的是修剪过的用户名
|
||
formData.set('password', password); // 确保发送的是修剪过的密码
|
||
formData.delete('confirm_password');
|
||
|
||
const response = await fetch(INIT_API_URL, {
|
||
method: 'POST',
|
||
body: new URLSearchParams(formData)
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
toast.show('管理员账户创建成功!正在跳转到登录页面...', 'success');
|
||
setTimeout(() => { window.location.href = '/login.html'; }, REDIRECT_DELAY_SUCCESS);
|
||
} else {
|
||
throw new Error(result.error || `初始化失败: ${response.status}`);
|
||
}
|
||
} catch (error) {
|
||
toast.show(error.message, 'error');
|
||
DOMElements.initButton.disabled = false;
|
||
DOMElements.initButton.querySelector('span').textContent = '完成设置';
|
||
}
|
||
}
|
||
|
||
function initApp() {
|
||
theme.init();
|
||
|
||
if (DOMElements.initForm) {
|
||
DOMElements.initButton = DOMElements.initForm.querySelector('button[type="submit"]');
|
||
|
||
toast.init(DOMElements.toastContainer);
|
||
|
||
DOMElements.initForm.addEventListener('submit', handleInitSubmit);
|
||
} else {
|
||
console.error('Init form element not found. Script may not function correctly.');
|
||
}
|
||
}
|
||
|
||
initApp();
|
||
}); |