| |
| function showMessage(elementId, message, type = 'error') { |
| const messageEl = document.getElementById(elementId); |
| messageEl.textContent = message; |
| messageEl.className = `message ${type} show`; |
|
|
| |
| if (type === 'success') { |
| setTimeout(() => { |
| messageEl.classList.remove('show'); |
| }, 3000); |
| } |
| } |
|
|
| |
| function hideMessage(elementId) { |
| const messageEl = document.getElementById(elementId); |
| messageEl.classList.remove('show'); |
| } |
|
|
| |
| function sha256(message) { |
| |
| if (typeof CryptoJS !== 'undefined' && CryptoJS.SHA256) { |
| return CryptoJS.SHA256(message).toString(); |
| } else { |
| console.error(window.t ? window.t('error.cryptoJsNotLoaded') : 'crypto-js库未加载,请检查CDN连接'); |
| throw new Error(window.t ? window.t('error.encryptionLibraryNotLoaded') : '加密库未加载'); |
| } |
| } |
|
|
| |
|
|
| |
| function hashPassword(password) { |
| return sha256(password); |
| } |
|
|
| |
| function hashPasswordWithTimestamp(password) { |
| |
| const passwordHash = sha256(password); |
| |
| const timestamp = Math.floor(Date.now() / 1000); |
| |
| const finalHash = sha256(`${passwordHash}:${timestamp}`); |
| return { hash: finalHash, timestamp: timestamp }; |
| } |
|
|
| function initPasswordToggle(inputId, toggleId) { |
| const input = document.getElementById(inputId); |
| const toggle = document.getElementById(toggleId); |
| if (!input || !toggle) return; |
|
|
| const showLabel = () => (window.t ? window.t('auth.showPassword') : '显示密码'); |
| const hideLabel = () => (window.t ? window.t('auth.hidePassword') : '隐藏密码'); |
|
|
| const updateToggleLabel = (visible) => { |
| const label = visible ? hideLabel() : showLabel(); |
| toggle.setAttribute('aria-label', label); |
| toggle.setAttribute('title', label); |
| }; |
|
|
| toggle.addEventListener('click', () => { |
| const visible = input.type === 'text'; |
| input.type = visible ? 'password' : 'text'; |
| toggle.classList.toggle('is-visible', !visible); |
| updateToggleLabel(!visible); |
| }); |
|
|
| updateToggleLabel(false); |
| } |
|
|
| initPasswordToggle('login-password', 'login-password-toggle'); |
|
|
| |
| document.querySelectorAll('.tab-btn').forEach(btn => { |
| btn.addEventListener('click', () => { |
| const tab = btn.dataset.tab; |
|
|
| |
| document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); |
| btn.classList.add('active'); |
|
|
| |
| document.querySelectorAll('.form-container').forEach(form => { |
| form.classList.remove('active'); |
| }); |
|
|
| if (tab === 'login') { |
| document.getElementById('login-form').classList.add('active'); |
| } else { |
| document.getElementById('register-form').classList.add('active'); |
| } |
|
|
| |
| hideMessage('login-message'); |
| hideMessage('register-message'); |
| }); |
| }); |
|
|
| |
| document.getElementById('loginForm').addEventListener('submit', async (e) => { |
| e.preventDefault(); |
|
|
| const form = e.target; |
| const submitBtn = form.querySelector('button[type="submit"]'); |
| const username = document.getElementById('login-username').value.trim(); |
| const password = document.getElementById('login-password').value; |
|
|
| |
| hideMessage('login-message'); |
|
|
| |
| submitBtn.disabled = true; |
| submitBtn.textContent = t('common.loggingIn'); |
|
|
| try { |
| |
| const { hash: passwordHash, timestamp } = hashPasswordWithTimestamp(password); |
|
|
| |
| const data = await apiPost('/users/login', { |
| username, |
| password: passwordHash, |
| timestamp: timestamp |
| }, { requireAuth: false }); |
|
|
| |
| saveToken(data.access_token); |
| showMessage('login-message', t('auth.loginSuccess', { username: data.user.username }) || `登录成功!欢迎,${data.user.username}`, 'success'); |
|
|
| |
| const urlParams = new URLSearchParams(window.location.search); |
| const redirectUrl = urlParams.get('redirect'); |
|
|
| |
| setTimeout(() => { |
| if (redirectUrl) { |
| window.location.href = decodeURIComponent(redirectUrl); |
| } else if (data.user.is_superuser) { |
| window.location.href = '/manager'; |
| } else { |
| window.location.href = '/user'; |
| } |
| }, 2000); |
| } catch (error) { |
| console.error(t('error.loginFailedCheckCredentials') || '登录错误:', error); |
| |
| const errorMessage = error.data?.detail || error.message || t('error.loginFailedCheckCredentials'); |
| showMessage('login-message', errorMessage, 'error'); |
| } finally { |
| |
| submitBtn.disabled = false; |
| submitBtn.textContent = t('common.login'); |
| } |
| }); |
|
|
| |
| document.getElementById('registerForm').addEventListener('submit', async (e) => { |
| e.preventDefault(); |
|
|
| const form = e.target; |
| const submitBtn = form.querySelector('button[type="submit"]'); |
| const username = document.getElementById('register-username').value.trim(); |
| const password = document.getElementById('register-password').value; |
| const fullName = document.getElementById('register-fullname').value.trim(); |
| const organization = document.getElementById('register-organization').value; |
| const team = document.getElementById('register-team').value.trim(); |
| const species = document.getElementById('register-species').value.trim(); |
|
|
| |
| hideMessage('register-message'); |
|
|
| |
| if (username.length < 3) { |
| showMessage('register-message', t('error.usernameMinLength'), 'error'); |
| return; |
| } |
|
|
| if (password.length < 6) { |
| showMessage('register-message', t('error.passwordMinLength'), 'error'); |
| return; |
| } |
|
|
| |
| submitBtn.disabled = true; |
| submitBtn.textContent = t('common.registering'); |
|
|
| try { |
| |
| const passwordHash = hashPassword(password); |
|
|
| |
| const data = await apiPost('/users/register', { |
| username, |
| password: passwordHash, |
| full_name: fullName || null, |
| organization: organization || null, |
| team: team || null, |
| species: species || null |
| }, { requireAuth: false }); |
|
|
| |
| showMessage('register-message', t('auth.registerSuccess', { username: data.username }) || `注册成功!用户名:${data.username}`, 'success'); |
|
|
| |
| form.reset(); |
|
|
| |
| setTimeout(() => { |
| document.querySelector('.tab-btn[data-tab="login"]').click(); |
| document.getElementById('login-username').value = username; |
| }, 2000); |
| } catch (error) { |
| console.error(t('error.registerFailedTryAgain') || '注册错误:', error); |
| |
| const errorMessage = error.data?.detail || error.message || t('error.registerFailedTryAgain'); |
| showMessage('register-message', errorMessage, 'error'); |
| } finally { |
| |
| submitBtn.disabled = false; |
| submitBtn.textContent = t('common.register'); |
| } |
| }); |
|
|
| |
| window.addEventListener('DOMContentLoaded', () => { |
| if (isLoggedIn()) { |
| |
| |
| } |
| }); |
|
|