Files
phaten-audio/en/docs/login/index.md
PhatenIoT-yan 00f42eab80 update
2025-12-25 14:21:26 +08:00

23 KiB

title
title
Login & Register

Login & Register

<style> /* Page version login/register styles */ .login-page-container { max-width: 500px; margin: 2rem auto; padding: 30px; background-color: #fefefe; border: 1px solid #ddd; border-radius: 15px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); } .login-page-container h2 { text-align: center; margin-bottom: 25px; color: #333; font-size: 24px; } /* Tab styles */ .tab-container { display: flex; margin-bottom: 25px; border-bottom: 1px solid #ddd; } .tab-button { flex: 1; padding: 15px; background: none; border: none; cursor: pointer; font-size: 16px; transition: all 0.3s ease; border-bottom: 2px solid transparent; } .tab-button.active { color: #3498db; border-bottom-color: #3498db; font-weight: bold; } .tab-button:hover { color: #3498db; background-color: #f8f9fa; } .tab-content { display: none; } .tab-content.active { display: block; } .login-form input { width: 100%; padding: 12px; margin: 12px 0; border: 1px solid #ddd; border-radius: 8px; box-sizing: border-box; font-size: 15px; } .login-form .code-container { display: flex; gap: 10px; margin: 12px 0; } .login-form .hint-text { font-size: 12px; color: #666; margin-top: 3px; margin-bottom: 8px; text-align: left; } .login-form .code-input { flex: 3; padding: 12px; border: 1px solid #ddd; border-radius: 8px; box-sizing: border-box; font-size: 15px; } .login-form .send-code-btn { flex: 1; min-width: 100px; padding: 12px 10px; height: 47px; background-color: #3498db; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; transition: background-color 0.3s ease; white-space: nowrap; box-sizing: border-box; display: flex; align-items: center; justify-content: center; } .login-form .send-code-btn:hover { background-color: #2980b9; } .login-form .send-code-btn:disabled { background-color: #95a5a6; cursor: not-allowed; } .login-form button[type="submit"] { width: 100%; padding: 12px; background-color: #3498db; color: white; border: none; border-radius: 8px; cursor: pointer; margin-top: 15px; font-size: 16px; transition: background-color 0.3s ease; } .login-form button[type="submit"]:hover { background-color: #2980b9; } /* Forgot password link styles */ .forgot-password-link { display: block; text-align: center; margin-top: 15px; color: #3498db; text-decoration: none; font-size: 14px; transition: color 0.3s ease; } .forgot-password-link:hover { color: #2980b9; text-decoration: underline; } /* Message prompt styles */ .message-box { display: none; padding: 15px; margin: 15px 0; border-radius: 8px; text-align: center; } .message-box.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .message-box.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .message-box.info { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; } </style>

Phaten Login/Register

<!-- Message prompt box -->
<div id="messageBox" class="message-box">
    <span id="messageText"></span>
</div>

<!-- Tab toggle buttons -->
<div class="tab-container">
    <button class="tab-button active" onclick="switchTab('login')">Login</button>
    <button class="tab-button" onclick="switchTab('register')">Register</button>
</div>

<!-- Login form -->
<div id="loginTab" class="tab-content active">
    <form id="loginForm" class="login-form">
        <input type="email" id="loginEmail" placeholder="Enter your email" required>
        <input type="password" id="loginPassword" placeholder="Enter your password" required>
        <button type="submit">Login</button>
        <a href="javascript:void(0)" class="forgot-password-link" onclick="switchTab('reset')">Forgot Password?</a>
    </form>
</div>

<!-- Register form -->
<div id="registerTab" class="tab-content">
    <form id="registerForm" class="login-form">
        <input type="email" id="registerEmail" placeholder="Enter your email" required>
        <div class="code-container">
            <input type="text" id="verificationCode" class="code-input" placeholder="Enter verification code" required>
            <button type="button" id="sendCodeBtn" class="send-code-btn">Send Code</button>
        </div>
        <input type="password" id="registerPassword" placeholder="Enter your password" required>
        <input type="password" id="confirmPassword" placeholder="Confirm your password" required>
        <button type="submit">Register</button>
    </form>
</div>

<!-- Forgot password form -->
<div id="resetTab" class="tab-content">
    <form id="resetForm" class="login-form">
        <input type="email" id="resetEmail" placeholder="Enter your email" required>
        <div class="code-container">
            <input type="text" id="resetVerificationCode" class="code-input" placeholder="Enter verification code" required>
            <button type="button" id="sendResetCodeBtn" class="send-code-btn">Send Code</button>
        </div>
        <input type="password" id="resetPassword" placeholder="Enter new password" required>
        <input type="password" id="resetConfirmPassword" placeholder="Confirm new password" required>
        <button type="submit">Reset Password</button>
        <a href="javascript:void(0)" class="forgot-password-link" onclick="switchTab('login')">Back to Login</a>
    </form>
</div>
<script> // Page version login/register functionality (function() { 'use strict'; // Define API base URL const baseUrl = 'https://api.phaten-audio.com/api'; //const baseUrl = 'http://localhost:8010/api'; // Get form elements const loginForm = document.getElementById("loginForm"); const registerForm = document.getElementById("registerForm"); const resetForm = document.getElementById("resetForm"); const sendCodeBtn = document.getElementById("sendCodeBtn"); const sendResetCodeBtn = document.getElementById("sendResetCodeBtn"); const messageBox = document.getElementById("messageBox"); const messageText = document.getElementById("messageText"); let countdownTimer; let resetCountdownTimer; // Tab switching functionality window.switchTab = function(tabName) { // Get tab container const tabContainer = document.querySelector('.tab-container'); // Hide all tab content const tabContents = document.querySelectorAll('.tab-content'); tabContents.forEach(tab => tab.classList.remove('active')); // Remove active state from all tab buttons const tabButtons = document.querySelectorAll('.tab-button'); tabButtons.forEach(btn => btn.classList.remove('active')); // Show corresponding tab content and set button active state if (tabName === 'login') { // Show tab container tabContainer.style.display = 'flex'; document.getElementById('loginTab').classList.add('active'); document.querySelectorAll('.tab-button')[0].classList.add('active'); } else if (tabName === 'register') { // Show tab container tabContainer.style.display = 'flex'; document.getElementById('registerTab').classList.add('active'); document.querySelectorAll('.tab-button')[1].classList.add('active'); } else if (tabName === 'reset') { // Hide tab container when in forgot password panel tabContainer.style.display = 'none'; document.getElementById('resetTab').classList.add('active'); } // Hide message box hideMessage(); } // Show message function showMessage(text, type = 'info') { messageText.textContent = text; messageBox.className = `message-box ${type}`; messageBox.style.display = 'block'; // Auto hide success and info messages after 3 seconds if (type === 'success' || type === 'info') { setTimeout(() => { hideMessage(); }, 3000); } } // Hide message function hideMessage() { messageBox.style.display = 'none'; } // Check if token exists in local storage function getLocalToken() { return localStorage.getItem('ftyToken'); } // Save token to local storage function saveToken(token) { localStorage.setItem('ftyToken', token); } // Clear token function clearToken() { localStorage.removeItem('ftyToken'); } // Validate if token is valid async function validateToken() { const token = getLocalToken(); console.log("validateToken function called, token:", token); if (!token) { console.log("No token, return false"); return false; } try { console.log("Sending token validation request..."); const response = await fetch(`${baseUrl}/fty/validateToken`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); const data = await response.json(); console.log("Token validation server response:", data); const isValid = data.data && data.data.valid === true; console.log("Is token valid:", isValid); // If token is invalid, clear local storage if (!isValid) { console.log("Token invalid, clear local storage"); clearToken(); } return isValid; } catch (error) { console.error('Token validation error:', error); console.log("Token validation error, clear local storage"); clearToken(); return false; } } // Validate email format function validateEmail(email) { const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(String(email).toLowerCase()); } // Send register verification code sendCodeBtn.onclick = function() { const contactValue = document.getElementById('registerEmail').value; if (!validateEmail(contactValue)) { showMessage('Please enter a valid email address!', 'error'); return; } // Disable button and start countdown startCountdown(); // Send AJAX request to get verification code fetch(`${baseUrl}/fty/sendCode`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ type: "1", // Fixed as email type username: contactValue }) }) .then(response => response.json()) .then(data => { console.log("Verification code send response", data); if (data.code==2000) { showMessage('Verification code has been sent to your email!', 'success'); } else { showMessage(data.msg || 'Failed to send verification code, please try again later!', 'error'); resetCountdown(); } }) .catch(error => { console.error('Error:', error); showMessage('Failed to send verification code request, please try again later!', 'error'); resetCountdown(); }); } // Send reset password verification code sendResetCodeBtn.onclick = function() { const contactValue = document.getElementById('resetEmail').value; if (!validateEmail(contactValue)) { showMessage('Please enter a valid email address!', 'error'); return; } // Disable button and start countdown startResetCountdown(); // Send AJAX request to get verification code fetch(`${baseUrl}/fty/sendCode`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ type: "1", // Fixed as email type username: contactValue }) }) .then(response => response.json()) .then(data => { console.log("Reset password verification code send response", data); if (data.code==2000) { showMessage('Verification code has been sent to your email!', 'success'); } else { showMessage(data.msg || 'Failed to send verification code, please try again later!', 'error'); resetResetCountdown(); } }) .catch(error => { console.error('Error:', error); showMessage('Failed to send verification code request, please try again later!', 'error'); resetResetCountdown(); }); } // Start register verification code countdown function startCountdown() { let countdown = 60; sendCodeBtn.disabled = true; sendCodeBtn.textContent = `Retry after ${countdown}s`; countdownTimer = setInterval(() => { countdown--; sendCodeBtn.textContent = `Retry after ${countdown}s`; if (countdown <= 0) { resetCountdown(); } }, 1000); } // Reset register verification code countdown function resetCountdown() { clearInterval(countdownTimer); sendCodeBtn.disabled = false; sendCodeBtn.textContent = 'Send Code'; } // Start reset password verification code countdown function startResetCountdown() { let countdown = 60; sendResetCodeBtn.disabled = true; sendResetCodeBtn.textContent = `Retry after ${countdown}s`; resetCountdownTimer = setInterval(() => { countdown--; sendResetCodeBtn.textContent = `Retry after ${countdown}s`; if (countdown <= 0) { resetResetCountdown(); } }, 1000); } // Reset reset password verification code countdown function resetResetCountdown() { clearInterval(resetCountdownTimer); sendResetCodeBtn.disabled = false; sendResetCodeBtn.textContent = 'Send Code'; } // Handle login form submission loginForm.onsubmit = function(e) { console.log("Login form submitted"); e.preventDefault(); const email = document.getElementById("loginEmail").value; const password = document.getElementById("loginPassword").value; if (!validateEmail(email)) { showMessage('Please enter a valid email address!', 'error'); return; } if (!password) { showMessage('Please enter your password!', 'error'); return; } // Show loading state const submitBtn = loginForm.querySelector('button[type="submit"]'); const originalText = submitBtn.textContent; submitBtn.textContent = 'Logging in...'; submitBtn.disabled = true; // Send AJAX request fetch(`${baseUrl}/fty/userLogin`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: email, type: 1, password: password }) }) .then(response => response.json()) .then(data => { console.log("Login response", data); if (data.code==2000) { // Save token to local storage if (data.data.token) { saveToken(data.data.token); } showMessage('Login successful! Redirecting...', 'success'); // Delay redirect to homepage setTimeout(() => { window.location.href = '/'; }, 1500); } else { showMessage(data.msg || 'Login failed, please check your email and password!', 'error'); } }) .catch(error => { console.error('Error:', error); var msg = error.message || error.toString() || error; showMessage('Login failed!',msg, 'error'); }) .finally(() => { // Restore button state submitBtn.textContent = originalText; submitBtn.disabled = false; }); } // Handle register form submission registerForm.onsubmit = function(e) { console.log("Register form submitted"); e.preventDefault(); const email = document.getElementById("registerEmail").value; const verificationCode = document.getElementById("verificationCode").value; const password = document.getElementById("registerPassword").value; const confirmPassword = document.getElementById("confirmPassword").value; if (!validateEmail(email)) { showMessage('Please enter a valid email address!', 'error'); return; } if (!verificationCode) { showMessage('Please enter verification code!', 'error'); return; } if (!password) { showMessage('Please enter your password!', 'error'); return; } if (password !== confirmPassword) { showMessage('The two passwords entered are inconsistent!', 'error'); return; } // Show loading state const submitBtn = registerForm.querySelector('button[type="submit"]'); const originalText = submitBtn.textContent; submitBtn.textContent = 'Registering...'; submitBtn.disabled = true; // Send AJAX request fetch(`${baseUrl}/fty/userRegister`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 1, // Fixed as email type username: email, code: verificationCode, password: password, confirm_password: confirmPassword }) }) .then(response => response.json()) .then(data => { console.log("Register response", data); if (data.code==2000) { // Save token to local storage if (data.data.token) { saveToken(data.data.token); } showMessage('Registration successful! Redirecting...', 'success'); resetCountdown(); // Delay redirect to homepage setTimeout(() => { window.location.href = '/'; }, 1500); } else { showMessage(data.msg || 'Registration failed, please check your input!', 'error'); } }) .catch(error => { console.error('Error:', error); var msg = error.message || error.toString() || error; showMessage('Registration failed',msg, 'error'); }) .finally(() => { // Restore button state submitBtn.textContent = originalText; submitBtn.disabled = false; }); } // Handle forgot password form submission resetForm.onsubmit = function(e) { console.log("Reset password form submitted"); e.preventDefault(); const email = document.getElementById("resetEmail").value; const verificationCode = document.getElementById("resetVerificationCode").value; const password = document.getElementById("resetPassword").value; const confirmPassword = document.getElementById("resetConfirmPassword").value; if (!validateEmail(email)) { showMessage('Please enter a valid email address!', 'error'); return; } if (!verificationCode) { showMessage('Please enter verification code!', 'error'); return; } if (!password) { showMessage('Please enter new password!', 'error'); return; } if (password !== confirmPassword) { showMessage('The two passwords entered are inconsistent!', 'error'); return; } // Show loading state const submitBtn = resetForm.querySelector('button[type="submit"]'); const originalText = submitBtn.textContent; submitBtn.textContent = 'Resetting...'; submitBtn.disabled = true; // Send AJAX request fetch(`${baseUrl}/fty/resetpwd`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 1, // Fixed as email type username: email, code: verificationCode, password: password, confirm_password: confirmPassword }) }) .then(response => response.json()) .then(data => { console.log("Reset password response", data); if (data.code==2000) { showMessage('Password reset successful! Please login with your new password', 'success'); resetResetCountdown(); // Delay switch to login tab setTimeout(() => { switchTab('login'); // Clear reset form resetForm.reset(); }, 1500); } else { showMessage(data.msg || 'Password reset failed, please check your input!', 'error'); } }) .catch(error => { console.error('Error:', error); showMessage('Password reset request failed, please try again later!', 'error'); }) .finally(() => { // Restore button state submitBtn.textContent = originalText; submitBtn.disabled = false; }); } // Check login status when page loads document.addEventListener('DOMContentLoaded', async function() { const isLoggedIn = await validateToken(); if (isLoggedIn) { showMessage('You are already logged in, redirecting to homepage...', 'info'); setTimeout(() => { window.location.href = '/'; }, 2000); } }); })(); // End of immediately invoked function </script>