Files
phaten-audio/zh/docs/common/checklogin_form.md
PhatenIoT-yan 00f42eab80 update
2025-12-25 14:21:26 +08:00

942 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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: 10% auto;
padding: 20px;
border: 1px solid #888;
width: 400px;
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.login-content h2 {
text-align: center;
margin-bottom: 15px;
color: #333;
font-size: 22px;
}
/* Tab 样式 */
.tab-container {
display: flex;
margin-bottom: 20px;
border-bottom: 1px solid #ddd;
}
.tab-button {
flex: 1;
padding: 12px;
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: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 8px;
box-sizing: border-box;
font-size: 15px;
}
.login-form .code-container {
display: flex;
gap: 10px;
margin: 10px 0;
}
.login-form .hint-text {
font-size: 12px;
color: #666;
margin-top: 3px;
margin-bottom: 3px;
text-align: left;
}
.login-form .code-input {
flex: 3;
padding: 10px;
border: 1px solid #ddd;
border-radius: 8px;
box-sizing: border-box;
font-size: 15px;
}
.login-form .send-code-btn {
flex: 1;
min-width: 95px;
padding: 0 8px;
background-color: #3498db;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s ease;
white-space: nowrap;
}
.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: 10px;
background-color: #3498db;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
margin-top: 12px;
font-size: 16px;
transition: background-color 0.3s ease;
}
.login-form button[type="submit"]:hover {
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;
font-size: 24px;
color: #666;
transition: color 0.3s ease;
}
.close:hover {
color: #333;
}
/* 消息弹出框样式 */
.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-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>
<!-- 消息弹出框 -->
<div id="messageModal" class="message-modal">
<div class="message-content">
<span class="close-message">&times;</span>
<h3 id="messageTitle">提示</h3>
<p id="messageText"></p>
<button id="messageBtn" class="message-btn">确定</button>
</div>
</div>
<div id="loginModal" class="login-modal">
<div class="login-content">
<span class="close" onclick="closeLoginModal()">&times;</span>
<h2>飞腾云登录/注册</h2>
<!-- Tab 切换按钮 -->
<div class="tab-container">
<button class="tab-button active" onclick="switchTab('login')">登录</button>
<button class="tab-button" onclick="switchTab('register')">注册</button>
</div>
<!-- 登录表单 -->
<div id="loginTab" class="tab-content active">
<form id="loginForm" class="login-form">
<input type="email" id="loginEmail" placeholder="请输入邮箱" required>
<input type="password" id="loginPassword" placeholder="请输入密码" required>
<button type="submit">登录</button>
<a href="javascript:void(0)" class="forgot-password-link" onclick="switchTab('reset')">忘记密码?</a>
</form>
</div>
<!-- 注册表单 -->
<div id="registerTab" class="tab-content">
<form id="registerForm" class="login-form">
<input type="email" id="registerEmail" placeholder="请输入邮箱" required>
<div class="code-container">
<input type="text" id="verificationCode" class="code-input" placeholder="请输入验证码" required>
<button type="button" id="sendCodeBtn" class="send-code-btn">发送验证码</button>
</div>
<input type="password" id="registerPassword" placeholder="请输入密码" required>
<input type="password" id="confirmPassword" placeholder="请确认密码" required>
<button type="submit">注册</button>
</form>
</div>
<!-- 忘记密码表单 -->
<div id="resetTab" class="tab-content">
<form id="resetForm" class="login-form">
<input type="email" id="resetEmail" placeholder="请输入邮箱" required>
<div class="code-container">
<input type="text" id="resetVerificationCode" class="code-input" placeholder="请输入验证码" required>
<button type="button" id="sendResetCodeBtn" class="send-code-btn">发送验证码</button>
</div>
<input type="password" id="resetPassword" placeholder="请输入新密码" required>
<input type="password" id="resetConfirmPassword" placeholder="请确认新密码" required>
<button type="submit">重置密码</button>
<a href="javascript:void(0)" class="forgot-password-link" onclick="switchTab('login')">返回登录</a>
</form>
</div>
</div>
</div>
<script>
// 避免重复声明,使用立即执行函数创建作用域
(function() {
'use strict';
// 定义API的基础URL
const baseUrl = 'https://api.phaten-audio.com/api';
//const baseUrl = 'http://localhost:8010/api';
// 获取模态框元素
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");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
const closeMessage = document.getElementsByClassName("close-message")[0];
// 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'));
// 移除所有tab按钮的active状态
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(btn => btn.classList.remove('active'));
// 显示对应的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');
}
}
// 显示自定义消息弹出框
function showMessage(title, text, type = 'info') {
messageTitle.textContent = title;
messageText.textContent = text;
// 根据类型设置样式
messageText.className = type === 'success' ? 'success' : (type === 'error' ? 'error' : '');
messageModal.style.display = "block";
}
// 关闭消息弹出框
function closeMessageModal() {
messageModal.style.display = "none";
}
// 绑定消息弹出框关闭事件
closeMessage.onclick = closeMessageModal;
messageBtn.onclick = closeMessageModal;
// 添加登录框关闭按钮
function closeLoginModal() {
console.log("用户关闭了登录模态框");
modal.style.display = "none";
// 清除待下载的URL因为用户取消了登录
const pendingUrl = sessionStorage.getItem('pendingDownloadUrl');
if (pendingUrl) {
console.log("清除待下载URL:", pendingUrl);
sessionStorage.removeItem('pendingDownloadUrl');
}
// 恢复下载按钮状态
const downloadBtn = document.getElementById('designDownloadBtn');
if (downloadBtn) {
downloadBtn.classList.remove('loading');
downloadBtn.innerHTML = '下载';
console.log("恢复下载按钮状态");
}
}
// 点击消息模态框外部关闭(只关闭消息框,不关闭登录框)
window.addEventListener('click', function(event) {
if (event.target == messageModal) {
closeMessageModal();
}
// 点击登录框外部也可以关闭
if (event.target == modal) {
closeLoginModal();
}
});
// 检查本地存储中是否有token
function getLocalToken() {
return localStorage.getItem('ftyToken');
}
// 保存token到本地存储
function saveToken(token) {
localStorage.setItem('ftyToken', token);
}
// 清除token
function clearToken() {
localStorage.removeItem('ftyToken');
}
// 验证token是否有效
async function validateToken() {
const token = getLocalToken();
console.log("validateToken函数被调用token:", token);
if (!token) {
console.log("没有token返回false");
return false;
}
try {
console.log("发送token验证请求...");
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验证服务器响应:",data);
const isValid = data.data && data.data.valid === true;
console.log("token是否有效:", isValid);
// 如果token无效清除本地存储
if (!isValid) {
console.log("token无效清除本地存储");
clearToken();
}
return isValid;
} catch (error) {
console.error('Token validation error:', error);
console.log("token验证出错清除本地存储");
clearToken();
return false;
}
}
// 检查登录状态
async function checkLogin(downloadUrl = null) {
// 获取触发按钮并添加loading状态
const downloadBtn = document.getElementById('designDownloadBtn');
if (downloadBtn) {
downloadBtn.classList.add('loading');
downloadBtn.innerHTML = '...';
}
try {
// 检查token是否有效
console.log("开始验证token...");
const token = getLocalToken();
console.log("本地token:", token);
const isLoggedIn = await validateToken();
console.log("验证结果 isLoggedIn:",isLoggedIn);
if (!isLoggedIn) {
// 如果未登录,保存下载链接并显示登录模态框
if (downloadUrl) {
sessionStorage.setItem('pendingDownloadUrl', downloadUrl);
if (modal) {
modal.style.display = "block";
} else {
console.error("modal元素未找到!");
}
}
} else {
// 如果已登录,直接进行下载
if (downloadUrl) {
if (downloadBtn) {
downloadBtn.innerHTML = '下载中...';
}
window.location.href = downloadUrl;
}
}
} catch (error) {
console.error("登录验证出错:", error);
} finally {
// 恢复按钮状态(如果没有跳转的话)
if (downloadBtn && !downloadBtn.innerHTML.includes('下载中')) {
setTimeout(() => {
downloadBtn.classList.remove('loading');
downloadBtn.innerHTML = '下载';
}, 500);
}
}
}
// 发送验证码
sendCodeBtn.onclick = function() {
const contactValue = document.getElementById('registerEmail').value;
if (!validateEmail(contactValue)) {
showMessage('输入错误', '请输入有效的邮箱地址!', 'error');
return;
}
// 禁用按钮并开始倒计时
startCountdown();
// 发送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');
resetCountdown();
}
})
.catch(error => {
console.error('Error:', error);
showMessage('网络错误', '验证码发送请求失败,请稍后重试!', 'error');
resetCountdown();
});
}
// 发送重置密码验证码
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,}))$/;
return re.test(String(email).toLowerCase());
}
// 开始倒计时
function startCountdown() {
let countdown = 60;
sendCodeBtn.disabled = true;
sendCodeBtn.textContent = `${countdown}秒后重试`;
countdownTimer = setInterval(() => {
countdown--;
sendCodeBtn.textContent = `${countdown}秒后重试`;
if (countdown <= 0) {
resetCountdown();
}
}, 1000);
}
// 重置倒计时
function resetCountdown() {
clearInterval(countdownTimer);
sendCodeBtn.disabled = false;
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");
e.preventDefault();
const email = document.getElementById("loginEmail").value;
const password = document.getElementById("loginPassword").value;
if (!validateEmail(email)) {
showMessage('输入错误', '请输入有效的邮箱地址!', 'error');
return;
}
if (!password) {
showMessage('输入错误', '请输入密码!', 'error');
return;
}
// 发送AJAX请求
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("登录返回",data);
if (data.code==2000) {
// 保存token到本地存储
if (data.data.token) {
saveToken(data.data.token);
}
showMessage('登录成功', '登录成功!', 'success');
// 登录成功后关闭模态框
modal.style.display = "none";
// 检查是否有待下载的链接
const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl');
if (pendingDownloadUrl) {
sessionStorage.removeItem('pendingDownloadUrl');
// 延迟一下再跳转,让用户看到成功消息
setTimeout(() => {
const downloadBtn = document.getElementById('designDownloadBtn');
if (downloadBtn) {
downloadBtn.innerHTML = '下载中...';
}
window.location.href = pendingDownloadUrl;
}, 1500);
}
} else {
showMessage('登录失败', data.msg || '登录失败,请检查邮箱和密码!', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('网络错误', '登录请求失败,请稍后重试!', 'error');
});
}
// 处理注册表单提交
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('输入错误', '请输入有效的邮箱地址!', 'error');
return;
}
if (!verificationCode) {
showMessage('输入错误', '请输入验证码!', 'error');
return;
}
if (!password) {
showMessage('输入错误', '请输入密码!', 'error');
return;
}
if (password !== confirmPassword) {
showMessage('输入错误', '两次输入的密码不一致!', 'error');
return;
}
// 发送AJAX请求
fetch(`${baseUrl}/fty/register`, {
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) {
// 保存token到本地存储
if (data.data.token) {
saveToken(data.data.token);
}
showMessage('注册成功', '注册成功!', 'success');
// 注册成功后关闭模态框
modal.style.display = "none";
resetCountdown();
// 检查是否有待下载的链接
const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl');
if (pendingDownloadUrl) {
sessionStorage.removeItem('pendingDownloadUrl');
// 延迟一下再跳转,让用户看到成功消息
setTimeout(() => {
const downloadBtn = document.getElementById('designDownloadBtn');
if (downloadBtn) {
downloadBtn.innerHTML = '下载中...';
}
window.location.href = pendingDownloadUrl;
}, 1500);
}
} else {
showMessage('注册失败', data.msg || '注册失败,请检查输入信息!', 'error');
}
})
.catch(error => {
console.error('Error:', error);
var msg = error.message || error.toString() || error;
showMessage( '注册请求失败!', msg,'error');
});
}
// 处理忘记密码表单提交
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);
var msg = error.message || error.toString() || error;
showMessage('提交请求失败,请稍后重试',msg, 'error');
})
.finally(() => {
// 恢复按钮状态
submitBtn.textContent = originalText;
submitBtn.disabled = false;
});
}
// ESC键关闭登录框
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && modal.style.display === 'block') {
console.log("用户按ESC键关闭登录框");
closeLoginModal();
}
});
// 页面加载时自动验证token
document.addEventListener('DOMContentLoaded', async function() {
// 自动检查登录状态(但不自动弹出登录框)
await validateToken();
// 额外检查modal元素是否正确获取
console.log("页面加载完成modal元素:", modal);
});
// 将需要全局访问的函数暴露到window对象
window.checkLogin = checkLogin;
window.closeLoginModal = closeLoginModal;
})(); // 立即执行函数结束
</script>