diff --git a/en/docs/common/checklogin_form.md b/en/docs/common/checklogin_form.md index db0a25e..7da9305 100644 --- a/en/docs/common/checklogin_form.md +++ b/en/docs/common/checklogin_form.md @@ -148,6 +148,22 @@ 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; @@ -298,6 +314,7 @@ + Forgot Password? @@ -314,6 +331,21 @@ + + +
+
+ +
+ + +
+ + + + Back to Login +
+
@@ -329,8 +361,11 @@ 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"); @@ -341,6 +376,9 @@ // 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')); @@ -351,11 +389,19 @@ // 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'); } } @@ -558,6 +604,46 @@ }); } + // 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,}))$/; @@ -587,6 +673,29 @@ 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"); @@ -756,6 +865,83 @@ }); } + // 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') { diff --git a/en/docs/common/customer_form.md b/en/docs/common/customer_form.md index 880a501..bb4b020 100644 --- a/en/docs/common/customer_form.md +++ b/en/docs/common/customer_form.md @@ -105,6 +105,8 @@ + +
@@ -122,6 +124,10 @@ const companyInput = document.getElementById("company"); const emailInput = document.getElementById("email"); const topicSelect = document.getElementById("topic"); const contentTextarea = document.getElementById("content"); +const pageUrlInput = document.getElementById("pageUrl"); + +// Set current page URL to hidden field +pageUrlInput.value = window.location.href; // Get message modal elements const messageModal = document.getElementById("messageModal"); @@ -222,7 +228,8 @@ customerForm.onsubmit = function(event) { company: companyInput.value.trim(), email: emailInput.value.trim(), topic: topicSelect.value, - content: contentTextarea.value.trim() + content: contentTextarea.value.trim(), + pageUrl: pageUrlInput.value }; // Send AJAX request diff --git a/zh/docs/common/checklogin_form.md b/zh/docs/common/checklogin_form.md index 8d0db65..2d54f53 100644 --- a/zh/docs/common/checklogin_form.md +++ b/zh/docs/common/checklogin_form.md @@ -141,6 +141,22 @@ background-color: #2980b9; } +/* 忘记密码链接样式 */ +.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; @@ -291,6 +307,7 @@ + 忘记密码? @@ -307,6 +324,21 @@ + + +
+
+ +
+ + +
+ + + + 返回登录 +
+
@@ -323,8 +355,11 @@ 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; // 获取消息弹出框元素 const messageModal = document.getElementById("messageModal"); @@ -335,6 +370,9 @@ // Tab 切换功能 window.switchTab = function(tabName) { + // 获取tab容器 + const tabContainer = document.querySelector('.tab-container'); + // 隐藏所有tab内容 const tabContents = document.querySelectorAll('.tab-content'); tabContents.forEach(tab => tab.classList.remove('active')); @@ -345,11 +383,19 @@ // 显示对应的tab内容和设置按钮active状态 if (tabName === 'login') { + // 显示tab容器 + tabContainer.style.display = 'flex'; document.getElementById('loginTab').classList.add('active'); document.querySelector('.tab-button').classList.add('active'); } else if (tabName === 'register') { + // 显示tab容器 + tabContainer.style.display = 'flex'; document.getElementById('registerTab').classList.add('active'); document.querySelectorAll('.tab-button')[1].classList.add('active'); + } else if (tabName === 'reset') { + // 忘记密码面板时隐藏tab容器 + tabContainer.style.display = 'none'; + document.getElementById('resetTab').classList.add('active'); } } @@ -552,6 +598,46 @@ }); } + // 发送重置密码验证码 + sendResetCodeBtn.onclick = function() { + const contactValue = document.getElementById('resetEmail').value; + + if (!validateEmail(contactValue)) { + showMessage('输入错误', '请输入有效的邮箱地址!', 'error'); + return; + } + + // 禁用按钮并开始倒计时 + startResetCountdown(); + + // 发送AJAX请求获取验证码 + fetch(`${baseUrl}/fty/sendCode`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: "1", // 固定为邮箱类型 + username: contactValue + }) + }) + .then(response => response.json()) + .then(data => { + console.log("重置密码验证码发送返回",data); + if (data.code==2000) { + showMessage('发送成功', '验证码已发送到您的邮箱!', 'success'); + } else { + showMessage('发送失败', data.msg || '验证码发送失败,请稍后重试!', 'error'); + resetResetCountdown(); + } + }) + .catch(error => { + console.error('Error:', error); + showMessage('网络错误', '验证码发送请求失败,请稍后重试!', 'error'); + resetResetCountdown(); + }); + } + // 验证邮箱格式 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,}))$/; @@ -581,6 +667,29 @@ sendCodeBtn.textContent = '发送验证码'; } + // 开始重置密码验证码倒计时 + function startResetCountdown() { + let countdown = 60; + sendResetCodeBtn.disabled = true; + sendResetCodeBtn.textContent = `${countdown}秒后重试`; + + resetCountdownTimer = setInterval(() => { + countdown--; + sendResetCodeBtn.textContent = `${countdown}秒后重试`; + + if (countdown <= 0) { + resetResetCountdown(); + } + }, 1000); + } + + // 重置重置密码验证码倒计时 + function resetResetCountdown() { + clearInterval(resetCountdownTimer); + sendResetCodeBtn.disabled = false; + sendResetCodeBtn.textContent = '发送验证码'; + } + // 处理登录表单提交 loginForm.onsubmit = function(e) { console.log("Login form submitted"); @@ -728,6 +837,83 @@ }); } + // 处理忘记密码表单提交 + 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('输入错误', '请输入有效的邮箱地址!', 'error'); + return; + } + + if (!verificationCode) { + showMessage('输入错误', '请输入验证码!', 'error'); + return; + } + + if (!password) { + showMessage('输入错误', '请输入新密码!', 'error'); + return; + } + + if (password !== confirmPassword) { + showMessage('输入错误', '两次输入的密码不一致!', 'error'); + return; + } + + // 显示加载状态 + const submitBtn = resetForm.querySelector('button[type="submit"]'); + const originalText = submitBtn.textContent; + submitBtn.textContent = '重置中...'; + submitBtn.disabled = true; + + // 发送AJAX请求 + fetch(`${baseUrl}/fty/resetpwd`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: 1, // 固定为邮箱类型 + username: email, + code: verificationCode, + password: password, + confirm_password: confirmPassword + }) + }) + .then(response => response.json()) + .then(data => { + console.log("重置密码返回",data); + if (data.code==2000) { + showMessage('重置成功', '密码重置成功!请使用新密码登录', 'success'); + resetResetCountdown(); + + // 延迟切换到登录标签 + setTimeout(() => { + switchTab('login'); + // 清空重置表单 + resetForm.reset(); + }, 1500); + } else { + showMessage('重置失败', data.msg || '密码重置失败,请检查输入信息!', 'error'); + } + }) + .catch(error => { + console.error('Error:', error); + showMessage('网络错误', '密码重置请求失败,请稍后重试!', 'error'); + }) + .finally(() => { + // 恢复按钮状态 + submitBtn.textContent = originalText; + submitBtn.disabled = false; + }); + } + // ESC键关闭登录框 document.addEventListener('keydown', function(event) { if (event.key === 'Escape' && modal.style.display === 'block') { diff --git a/zh/docs/common/customer_form.md b/zh/docs/common/customer_form.md index f9763cd..443899c 100644 --- a/zh/docs/common/customer_form.md +++ b/zh/docs/common/customer_form.md @@ -105,6 +105,8 @@ + +
@@ -122,6 +124,10 @@ const companyInput = document.getElementById("company"); const emailInput = document.getElementById("email"); const topicSelect = document.getElementById("topic"); const contentTextarea = document.getElementById("content"); +const pageUrlInput = document.getElementById("pageUrl"); + +// 设置当前页面URL到隐藏字段 +pageUrlInput.value = window.location.href; // 获取消息弹出框元素 const messageModal = document.getElementById("messageModal"); @@ -222,7 +228,8 @@ customerForm.onsubmit = function(event) { company: companyInput.value.trim(), email: emailInput.value.trim(), topic: topicSelect.value, - content: contentTextarea.value.trim() + content: contentTextarea.value.trim(), + pageUrl: pageUrlInput.value }; // 发送AJAX请求