Files
phaten-audio/en/docs/common/checklogin_form.md
2025-08-06 14:42:54 +08:00

31 KiB
Raw Blame History

<style> .login-modal { display: none !important; position: fixed !important; z-index: 100 !important; left: 0 !important; top: 0 !important; width: 100% !important; height: 100% !important; background-color: rgba(0,0,0,0.5) !important; } .login-modal[style*="block"] { display: block !important; } .login-content { background-color: #fefefe; margin: 5% auto; padding: 30px; border: 1px solid #888; width: 450px; border-radius: 15px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); max-height: 90vh; overflow-y: auto; } .login-content 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; } .close { float: right; cursor: pointer; font-size: 24px; color: #666; transition: color 0.3s ease; } .close:hover { color: #333; } /* Message modal styles */ .message-modal { display: none; position: fixed; z-index: 1001; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); } .message-content { background-color: #fefefe; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 400px; border-radius: 15px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); text-align: center; } .message-content h3 { margin: 0 0 15px 0; color: #333; font-size: 18px; } .message-content p { margin: 15px 0; color: #666; line-height: 1.5; white-space: pre-line; } .message-content .success { color: #27ae60; } .message-content .error { color: #e74c3c; } .message-btn { background-color: #3498db; color: white; border: none; border-radius: 8px; padding: 10px 20px; cursor: pointer; font-size: 14px; margin-top: 10px; transition: background-color 0.3s ease; } .message-btn:hover { background-color: #2980b9; } .close-message { float: right; cursor: pointer; font-size: 24px; color: #666; transition: color 0.3s ease; } .close-message:hover { color: #333; } /* Download button styles */ .download-btn { font-size: 12px !important; padding: 6px 12px !important; min-height: auto !important; line-height: 1.2 !important; } .download-btn.loading { pointer-events: none; opacity: 0.7; position: relative; } .download-btn.loading::after { content: ""; position: absolute; width: 12px; height: 12px; top: 50%; left: 50%; margin-left: -6px; margin-top: -6px; border: 2px solid #ffffff; border-radius: 50%; border-top-color: transparent; animation: button-loading-spinner 1s ease infinite; } @keyframes button-loading-spinner { from { transform: rotate(0turn); } to { transform: rotate(1turn); } } </style>
×

Notice

OK
×

Phaten Cloud Login/Register

    <!-- 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>
</div>
<script> // Avoid duplicate declarations, use immediately invoked function to create scope (function() { 'use strict'; // Define API base URL const baseUrl = 'https://api.phaten-audio.com/api'; // Get modal elements const modal = document.getElementById("loginModal"); 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"); let countdownTimer; let resetCountdownTimer; // Get message modal elements const messageModal = document.getElementById("messageModal"); const messageTitle = document.getElementById("messageTitle"); const messageText = document.getElementById("messageText"); const messageBtn = document.getElementById("messageBtn"); const closeMessage = document.getElementsByClassName("close-message")[0]; // 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.querySelector('.tab-button').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'); } } // Show custom message modal function showMessage(title, text, type = 'info') { messageTitle.textContent = title; messageText.textContent = text; // Set style based on type messageText.className = type === 'success' ? 'success' : (type === 'error' ? 'error' : ''); messageModal.style.display = "block"; } // Close message modal function closeMessageModal() { messageModal.style.display = "none"; } // Bind message modal close events closeMessage.onclick = closeMessageModal; messageBtn.onclick = closeMessageModal; // Add login modal close button function closeLoginModal() { console.log("User closed login modal"); modal.style.display = "none"; // Clear pending download URL since user cancelled login const pendingUrl = sessionStorage.getItem('pendingDownloadUrl'); if (pendingUrl) { console.log("Clear pending download URL:", pendingUrl); sessionStorage.removeItem('pendingDownloadUrl'); } // Restore download button state const downloadBtn = document.getElementById('designDownloadBtn'); if (downloadBtn) { downloadBtn.classList.remove('loading'); downloadBtn.innerHTML = 'Download'; console.log("Restore download button state"); } } // Click outside message modal to close (only close message modal, not login modal) window.addEventListener('click', function(event) { if (event.target == messageModal) { closeMessageModal(); } // Click outside login modal can also close it if (event.target == modal) { closeLoginModal(); } }); // 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; } } // Check login status async function checkLogin(downloadUrl = null) { // Get trigger button and add loading state const downloadBtn = document.getElementById('designDownloadBtn'); if (downloadBtn) { downloadBtn.classList.add('loading'); downloadBtn.innerHTML = '...'; } try { // Check if token is valid console.log("Start validating token..."); const token = getLocalToken(); console.log("Local token:", token); const isLoggedIn = await validateToken(); console.log("Validation result isLoggedIn:", isLoggedIn); if (!isLoggedIn) { // If not logged in, save download link and show login modal if (downloadUrl) { sessionStorage.setItem('pendingDownloadUrl', downloadUrl); if (modal) { modal.style.display = "block"; } else { console.error("Modal element not found!"); } } } else { // If logged in, start download directly if (downloadUrl) { if (downloadBtn) { downloadBtn.innerHTML = 'Downloading...'; } window.location.href = downloadUrl; } } } catch (error) { console.error("Login verification error:", error); } finally { // Restore button state (if not redirected) if (downloadBtn && !downloadBtn.innerHTML.includes('Downloading')) { setTimeout(() => { downloadBtn.classList.remove('loading'); downloadBtn.innerHTML = 'Download'; }, 500); } } } // Send verification code sendCodeBtn.onclick = function() { const contactValue = document.getElementById('registerEmail').value; if (!validateEmail(contactValue)) { showMessage('Input Error', '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('Send Success', 'Verification code has been sent to your email!', 'success'); } else { showMessage('Send Failed', data.msg || 'Failed to send verification code, please try again later!', 'error'); resetCountdown(); } }) .catch(error => { console.error('Error:', error); showMessage('Network Error', '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('Input Error', '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('Send Success', 'Verification code has been sent to your email!', 'success'); } else { showMessage('Send Failed', data.msg || 'Failed to send verification code, please try again later!', 'error'); resetResetCountdown(); } }) .catch(error => { console.error('Error:', error); showMessage('Network Error', 'Failed to send verification code request, please try again later!', 'error'); resetResetCountdown(); }); } // 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()); } // Start 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 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('Input Error', 'Please enter a valid email address!', 'error'); return; } if (!password) { showMessage('Input Error', '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 Success', 'Login successful!', 'success'); // Close modal after successful login modal.style.display = "none"; // Check if there's a pending download link const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl'); if (pendingDownloadUrl) { sessionStorage.removeItem('pendingDownloadUrl'); // Delay a bit before redirect to let user see success message setTimeout(() => { const downloadBtn = document.getElementById('designDownloadBtn'); if (downloadBtn) { downloadBtn.innerHTML = 'Downloading...'; } window.location.href = pendingDownloadUrl; }, 1500); } } else { showMessage('Login Failed', data.msg || 'Login failed, please check your email and password!', 'error'); } }) .catch(error => { console.error('Error:', error); showMessage('Network Error', 'Login request failed, please try again later!', '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('Input Error', 'Please enter a valid email address!', 'error'); return; } if (!verificationCode) { showMessage('Input Error', 'Please enter verification code!', 'error'); return; } if (!password) { showMessage('Input Error', 'Please enter your password!', 'error'); return; } if (password !== confirmPassword) { showMessage('Input Error', '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('Register Success', 'Registration successful!', 'success'); // Close modal after successful registration modal.style.display = "none"; resetCountdown(); // Check if there's a pending download link const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl'); if (pendingDownloadUrl) { sessionStorage.removeItem('pendingDownloadUrl'); // Delay a bit before redirect to let user see success message setTimeout(() => { const downloadBtn = document.getElementById('designDownloadBtn'); if (downloadBtn) { downloadBtn.innerHTML = 'Downloading...'; } window.location.href = pendingDownloadUrl; }, 1500); } } else { showMessage('Register Failed', data.msg || 'Registration failed, please check your input!', 'error'); } }) .catch(error => { console.error('Error:', error); showMessage('Network Error', 'Registration request failed, please try again later!', '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('Input Error', 'Please enter a valid email address!', 'error'); return; } if (!verificationCode) { showMessage('Input Error', 'Please enter verification code!', 'error'); return; } if (!password) { showMessage('Input Error', 'Please enter new password!', 'error'); return; } if (password !== confirmPassword) { showMessage('Input Error', '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('Reset Success', '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('Reset Failed', data.msg || 'Password reset failed, please check your input!', 'error'); } }) .catch(error => { console.error('Error:', error); showMessage('Network Error', 'Password reset request failed, please try again later!', 'error'); }) .finally(() => { // Restore button state submitBtn.textContent = originalText; submitBtn.disabled = false; }); } // ESC key to close login modal document.addEventListener('keydown', function(event) { if (event.key === 'Escape' && modal.style.display === 'block') { console.log("User pressed ESC to close login modal"); closeLoginModal(); } }); // Auto validate token when page loads document.addEventListener('DOMContentLoaded', async function() { // Auto check login status (but don't auto show login modal) await validateToken(); // Additional check if modal element is correctly obtained console.log("Page loaded, modal element:", modal); }); // Expose globally accessible functions to window object window.checkLogin = checkLogin; window.closeLoginModal = closeLoginModal; })(); // End of immediately invoked function </script>