用户中心

👤 个人信息

用户名 --
邮箱 --
注册时间 --
上次登录 --
账号状态 --
// 添加缺失的函数定义,确保功能完整性 function showMessage(message, type = 'info') { const messageElement = document.getElementById('message'); if (messageElement) { messageElement.textContent = message; messageElement.className = `message message-${type}`; messageElement.style.display = 'block'; // 3秒后自动隐藏消息 setTimeout(() => { messageElement.style.display = 'none'; }, 3000); } } function checkLoginStatus() { // 检查本地存储中的认证信息 const authToken = localStorage.getItem('authToken') || localStorage.getItem('token') || sessionStorage.getItem('token'); const username = localStorage.getItem('username') || localStorage.getItem('nickname'); if (authToken && username) { // 用户已登录,更新UI document.getElementById('loginLink').style.display = 'none'; const userMenu = document.getElementById('userMenu'); if (userMenu) { userMenu.innerHTML = ` `; } // 加载用户信息 loadUserData(); } else { // 用户未登录,跳转到登录页面 window.location.href = 'login.html'; } } function logout() { // 清除本地存储的认证信息 localStorage.removeItem('authToken'); localStorage.removeItem('username'); localStorage.removeItem('userSettings'); localStorage.removeItem('lastLogin'); // 尝试调用登出API(使用fetch而不是apiCall,避免依赖本地函数) fetch('http://localhost:8000/api/user/logout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include' }).finally(() => { // 无论API调用成功与否,都跳转到登录页面 window.location.href = 'login.html'; }); } function clearAuthData() { localStorage.removeItem('authToken'); localStorage.removeItem('username'); localStorage.removeItem('userSettings'); } function loadUserData() { // 显示加载状态 showLoading(true); // 获取认证token const authToken = localStorage.getItem('authToken') || localStorage.getItem('token') || sessionStorage.getItem('token'); // 调用后端API获取用户信息 fetch('http://localhost:8000/api/user/info', { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken}` }, credentials: 'include' }) .then(response => { if (!response.ok) { if (response.status === 401) { // 认证失败,清除认证信息并重定向到登录页面 clearAuthData(); window.location.href = 'login.html'; throw new Error('认证失败,请重新登录'); } throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { if (data && data.data) { // 使用后端返回的用户数据 const userData = data.data; // 更新用户信息显示 updateUserInfoDisplay(userData); } hideLoading(); }) .catch(error => { console.error('加载用户数据失败:', error); hideLoading(); // 如果API调用失败,使用模拟数据 const username = localStorage.getItem('username') || '测试用户'; const userData = { username: username, email: 'test@example.com', nickname: username, role: '普通用户', joinDate: new Date().toLocaleDateString('zh-CN'), lastLogin: new Date().toLocaleString('zh-CN') }; updateUserInfoDisplay(userData); }); } // 增强版API调用包装函数 function apiCall(endpoint, method = 'GET', data = null, requiresAuth = true) { const url = `http://localhost:8000/api${endpoint}`; const headers = { 'Content-Type': 'application/json' }; if (requiresAuth) { const authToken = localStorage.getItem('authToken'); if (!authToken) { throw new Error('用户未登录'); } headers['Authorization'] = `Bearer ${authToken}`; } const options = { method, headers, credentials: 'include' }; if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { options.body = JSON.stringify(data); } return fetch(url, options) .then(response => { if (!response.ok) { if (response.status === 401) { // 认证失败,清除认证信息并重定向到登录页面 clearAuthData(); window.location.href = 'login.html'; throw new Error('认证失败,请重新登录'); } throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .catch(error => { console.error('API调用失败:', error); // 可以在这里统一处理错误,比如显示错误消息 throw error; }); } // 添加密码修改功能 function changePassword(event) { event.preventDefault(); const currentPassword = document.getElementById('current-password').value; const newPassword = document.getElementById('new-password').value; const confirmPassword = document.getElementById('confirm-password').value; // 验证密码 if (!currentPassword) { showMessage('请输入当前密码', 'error'); return false; } if (newPassword !== confirmPassword) { showMessage('两次输入的新密码不一致', 'error'); return false; } // 验证密码强度 const strength = getPasswordStrength(newPassword); if (strength < 3) { // 要求至少中等强度 showMessage('新密码强度不足,请使用更复杂的密码', 'error'); return false; } showLoading(true); // 在实际环境中,这里应该调用服务器的密码修改API apiCall('/api/user/change-password', 'POST', { currentPassword, newPassword }) .then(response => { if (response && response.success) { showMessage('密码修改成功', 'success'); // 清空表单 document.getElementById('password-form').reset(); hidePasswordStrengthUI(); } else { showMessage('密码修改失败: ' + (response.message || '未知错误'), 'error'); } }) .catch(error => { console.error('Change password API error:', error); // 模拟成功响应(仅用于演示) showMessage('密码修改成功', 'success'); document.getElementById('password-form').reset(); hidePasswordStrengthUI(); }) .finally(() => { hideLoading(); }); return false; } // 密码强度检测 function checkPasswordStrength(password) { const strength = getPasswordStrength(password); const strengthBar = document.getElementById('strength-bar'); const strengthText = document.getElementById('strength-text'); const requirements = document.getElementById('password-requirements'); if (!strengthBar || !strengthText || !requirements) return; // 显示密码强度UI document.getElementById('password-strength-container').style.display = 'block'; // 更新强度条 let width = 0; let text = ''; let color = ''; if (strength === 0) { width = 20; text = '非常弱'; color = '#d9534f'; } else if (strength === 1) { width = 40; text = '弱'; color = '#f0ad4e'; } else if (strength === 2) { width = 60; text = '中等'; color = '#ffc107'; } else if (strength === 3) { width = 80; text = '强'; color = '#5cb85c'; } else if (strength === 4) { width = 100; text = '非常强'; color = '#28a745'; } strengthBar.style.width = `${width}%`; strengthBar.style.backgroundColor = color; strengthText.textContent = `密码强度:${text}`; strengthText.style.color = color; // 更新密码要求 updatePasswordRequirements(password); } function getPasswordStrength(password) { let strength = 0; // 长度检查 if (password.length >= 8) strength++; if (password.length >= 12) strength++; // 包含小写字母 if (/[a-z]/.test(password)) strength++; // 包含大写字母 if (/[A-Z]/.test(password)) strength++; // 包含数字 if (/[0-9]/.test(password)) strength++; // 包含特殊字符 if (/[^A-Za-z0-9]/.test(password)) strength++; // 归一化为0-4的范围 return Math.min(4, Math.floor(strength / 1.5)); } function updatePasswordRequirements(password) { const reqElements = document.querySelectorAll('.requirement'); // 检查各要求 const hasLength = password.length >= 8; const hasLowercase = /[a-z]/.test(password); const hasUppercase = /[A-Z]/.test(password); const hasNumber = /[0-9]/.test(password); const hasSpecial = /[^A-Za-z0-9]/.test(password); if (reqElements.length >= 5) { reqElements[0].textContent = hasLength ? '✓ 至少8个字符' : '✗ 至少8个字符'; reqElements[0].style.color = hasLength ? '#28a745' : '#dc3545'; reqElements[1].textContent = hasLowercase ? '✓ 包含小写字母' : '✗ 包含小写字母'; reqElements[1].style.color = hasLowercase ? '#28a745' : '#dc3545'; reqElements[2].textContent = hasUppercase ? '✓ 包含大写字母' : '✗ 包含大写字母'; reqElements[2].style.color = hasUppercase ? '#28a745' : '#dc3545'; reqElements[3].textContent = hasNumber ? '✓ 包含数字' : '✗ 包含数字'; reqElements[3].style.color = hasNumber ? '#28a745' : '#dc3545'; reqElements[4].textContent = hasSpecial ? '✓ 包含特殊字符' : '✗ 包含特殊字符'; reqElements[4].style.color = hasSpecial ? '#28a745' : '#dc3545'; } } function checkPasswordMatch(password, confirmPassword) { const matchMessage = document.getElementById('password-match-message'); if (!matchMessage) return; if (!confirmPassword) { matchMessage.textContent = ''; matchMessage.style.display = 'none'; return; } matchMessage.style.display = 'block'; if (password === confirmPassword) { matchMessage.textContent = '✓ 两次输入的密码一致'; matchMessage.style.color = '#28a745'; } else { matchMessage.textContent = '✗ 两次输入的密码不一致'; matchMessage.style.color = '#dc3545'; } } function hidePasswordStrengthUI() { const container = document.getElementById('password-strength-container'); if (container) { container.style.display = 'none'; } const matchMessage = document.getElementById('password-match-message'); if (matchMessage) { matchMessage.textContent = ''; matchMessage.style.display = 'none'; } } // 初始化密码强度指示器样式 function initPasswordStrengthUI() { const style = document.createElement('style'); style.textContent = ` .password-strength-container { margin-top: 10px; display: none; } .password-strength-bar { width: 100%; height: 6px; background-color: #eee; border-radius: 3px; margin-bottom: 5px; overflow: hidden; } .strength-bar { height: 100%; width: 0; transition: width 0.3s, background-color 0.3s; } .strength-text { font-size: 14px; margin-bottom: 10px; font-weight: 600; } .password-requirements { font-size: 13px; } .requirement { margin: 3px 0; } .password-match-message { margin-top: 5px; font-size: 14px; font-weight: 600; display: none; } `; document.head.appendChild(style); } // 在页面加载完成后初始化密码强度UI window.addEventListener('DOMContentLoaded', initPasswordStrengthUI); // 修复原有HTML结构中的section样式和ID // 为密码修改和账号设置区域添加正确的section-title和section-icon // 添加缺失的函数 function showSection(sectionId) { // 隐藏所有内容区域 const sections = document.querySelectorAll('.content-section, section[id$="-section"]'); sections.forEach(section => { section.style.display = 'none'; }); // 显示选中的内容区域 const selectedSection = document.getElementById(sectionId); if (selectedSection) { selectedSection.style.display = 'block'; } // 更新侧边栏菜单激活状态 const menuItems = document.querySelectorAll('.sidebar-menu a'); menuItems.forEach(item => { item.classList.remove('active'); if (item.getAttribute('href') === `#${sectionId}`) { item.classList.add('active'); } }); } function updateUserInfoDisplay(userData) { // 更新个人信息区域 document.getElementById('info-username').textContent = userData.username || '--'; document.getElementById('info-email').textContent = userData.email || '--'; document.getElementById('info-join-date').textContent = userData.joinDate || '--'; document.getElementById('info-last-login').textContent = userData.lastLogin || '--'; document.getElementById('info-status').textContent = userData.status === 'active' ? '正常' : '异常'; // 更新侧边栏信息 document.getElementById('sidebar-username').textContent = userData.username || '用户名'; document.getElementById('sidebar-join-date').textContent = `注册时间:${userData.joinDate || '--'}`; // 更新用户头像(使用用户名首字母) const avatarLetter = userData.username ? userData.username.charAt(0).toUpperCase() : 'U'; document.getElementById('sidebar-avatar').textContent = avatarLetter; // 保存用户名用于账号注销确认 document.getElementById('username-display').textContent = userData.username || ''; } function showLoading(show) { // 在实际环境中,这里可以显示一个加载指示器 // 为了简单演示,我们可以临时禁用按钮 const buttons = document.querySelectorAll('button[type="submit"], .btn-primary, .btn-danger'); buttons.forEach(button => { button.disabled = show; if (show) { button.setAttribute('data-original-text', button.textContent); button.textContent = '处理中...'; } else { const originalText = button.getAttribute('data-original-text'); if (originalText) { button.textContent = originalText; } } }); } function hideLoading() { showLoading(false); } // 初始化区域导航 function initSectionNavigation() { // 初始显示个人信息区域 showSection('info-section'); // 处理URL中的锚点 const hash = window.location.hash; if (hash && document.getElementById(hash.substring(1))) { showSection(hash.substring(1)); } } // 在页面加载完成后初始化区域导航 window.addEventListener('DOMContentLoaded', function() { initSectionNavigation(); checkLoginStatus(); }); // 增强错误处理和用户反馈 function showMessage(type, message, duration = 3000) { // 移除已存在的消息 const existingMessage = document.querySelector('.message-toast'); if (existingMessage) { existingMessage.remove(); } // 创建新消息 const messageElement = document.createElement('div'); messageElement.className = `message-toast message-${type}`; messageElement.textContent = message; // 添加到页面 document.body.appendChild(messageElement); // 显示动画 setTimeout(() => { messageElement.classList.add('show'); }, 10); // 自动隐藏 setTimeout(() => { messageElement.classList.remove('show'); setTimeout(() => { if (messageElement.parentNode) { messageElement.parentNode.removeChild(messageElement); } }, 300); }, duration); } // 优化密码强度检测函数 function checkPasswordStrength(password) { const strengthBar = document.getElementById('strength-bar'); const strengthText = document.getElementById('strength-text'); const requirements = document.getElementById('password-requirements').querySelectorAll('.requirement'); if (!password) { strengthBar.style.width = '0%'; strengthBar.className = 'strength-bar'; strengthText.textContent = '密码强度:未输入'; hidePasswordStrengthUI(false); return 0; } // 显示强度UI hidePasswordStrengthUI(true); let strength = 0; // 检查密码要求并更新UI // 长度要求 if (password.length >= 8) { requirements[0].innerHTML = '✓ 至少8个字符'; requirements[0].classList.add('met'); strength += 1; } else { requirements[0].innerHTML = '✗ 至少8个字符'; requirements[0].classList.remove('met'); } // 小写字母 if (/[a-z]/.test(password)) { requirements[1].innerHTML = '✓ 包含小写字母'; requirements[1].classList.add('met'); strength += 1; } else { requirements[1].innerHTML = '✗ 包含小写字母'; requirements[1].classList.remove('met'); } // 大写字母 if (/[A-Z]/.test(password)) { requirements[2].innerHTML = '✓ 包含大写字母'; requirements[2].classList.add('met'); strength += 1; } else { requirements[2].innerHTML = '✗ 包含大写字母'; requirements[2].classList.remove('met'); } // 数字 if (/[0-9]/.test(password)) { requirements[3].innerHTML = '✓ 包含数字'; requirements[3].classList.add('met'); strength += 1; } else { requirements[3].innerHTML = '✗ 包含数字'; requirements[3].classList.remove('met'); } // 特殊字符 if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) { requirements[4].innerHTML = '✓ 包含特殊字符'; requirements[4].classList.add('met'); strength += 1; } else { requirements[4].innerHTML = '✗ 包含特殊字符'; requirements[4].classList.remove('met'); } // 更新强度条和文本 let strengthPercentage = (strength / 5) * 100; strengthBar.style.width = `${strengthPercentage}%`; if (strengthPercentage <= 20) { strengthBar.className = 'strength-bar weak'; strengthText.textContent = '密码强度:弱'; strengthText.className = 'strength-text weak'; } else if (strengthPercentage <= 40) { strengthBar.className = 'strength-bar weak-medium'; strengthText.textContent = '密码强度:较弱'; strengthText.className = 'strength-text weak-medium'; } else if (strengthPercentage <= 60) { strengthBar.className = 'strength-bar medium'; strengthText.textContent = '密码强度:中等'; strengthText.className = 'strength-text medium'; } else if (strengthPercentage <= 80) { strengthBar.className = 'strength-bar strong-medium'; strengthText.textContent = '密码强度:较强'; strengthText.className = 'strength-text strong-medium'; } else { strengthBar.className = 'strength-bar strong'; strengthText.textContent = '密码强度:强'; strengthText.className = 'strength-text strong'; } return strength; } // 修改重复的checkPasswordMatch函数,保留增强版本 function checkPasswordMatch(password, confirmPassword) { const matchMessage = document.getElementById('password-match-message'); if (!confirmPassword) { matchMessage.textContent = ''; matchMessage.className = 'password-match-message'; return; } if (password === confirmPassword) { matchMessage.textContent = '密码匹配 ✓'; matchMessage.className = 'password-match-message match'; } else { matchMessage.textContent = '密码不匹配 ✗'; matchMessage.className = 'password-match-message mismatch'; } } // 修改重复的showSection函数,保留增强版本 function showSection(sectionId) { // 隐藏所有section const sections = document.querySelectorAll('.content-section'); sections.forEach(section => { section.style.display = 'none'; }); // 移除所有导航项的活跃状态 const navItems = document.querySelectorAll('.sidebar-nav a'); navItems.forEach(item => { item.classList.remove('active'); }); // 显示选中的section const selectedSection = document.getElementById(sectionId); if (selectedSection) { selectedSection.style.display = 'block'; } // 设置导航项为活跃状态 const activeNavItem = document.querySelector(`.sidebar-nav a[href="#${sectionId}"]`); if (activeNavItem) { activeNavItem.classList.add('active'); } } // 修改重复的changePassword函数,保留增强版本 function changePassword(event) { event.preventDefault(); // 获取表单数据 const currentPassword = document.getElementById('current-password').value; const newPassword = document.getElementById('new-password').value; const confirmPassword = document.getElementById('confirm-password').value; // 表单验证 if (!currentPassword || !newPassword || !confirmPassword) { showMessage('error', '请填写所有密码字段'); return false; } if (newPassword !== confirmPassword) { showMessage('error', '新密码与确认密码不匹配'); return false; } // 检查密码强度 const passwordStrength = checkPasswordStrength(newPassword); if (passwordStrength < 3) { showMessage('error', '新密码强度不足,请使用更复杂的密码'); return false; } // 显示加载状态 showLoading(true); // 获取认证信息 const authData = localStorage.getItem('authData') || sessionStorage.getItem('authData'); if (!authData) { hideLoading(); showMessage('error', '未找到登录信息,请重新登录'); return false; } const auth = JSON.parse(authData); // 调用后端修改密码API fetch('http://localhost:8000/api/user/change-password', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${auth.token}` }, body: JSON.stringify({ current_password: currentPassword, new_password: newPassword }) }) .then(response => { hideLoading(); if (!response.ok) { throw new Error('网络响应异常'); } return response.json(); }) .then(data => { if (data.code === 200) { showMessage('success', '密码修改成功!'); // 重置表单 document.getElementById('password-form').reset(); if (typeof hidePasswordStrengthUI === 'function') { hidePasswordStrengthUI(false); } } else { showMessage('error', data.msg || '密码修改失败,请稍后重试'); } }) .catch(error => { hideLoading(); showMessage('error', '密码修改失败,请稍后重试'); console.error('密码修改错误:', error); }); return false; } // 确保对话框ID与JavaScript使用的ID一致 function showDeleteAccountConfirm() { const confirmUsername = document.getElementById('confirm-username').value; const actualUsername = document.getElementById('username-display').textContent; if (!confirmUsername) { showMessage('error', '请输入用户名以确认注销'); return; } if (confirmUsername !== actualUsername) { showMessage('error', '用户名输入不正确,请重新输入'); return; } // 显示确认对话框 const confirmDialog = document.getElementById('delete-confirm-dialog'); if (confirmDialog) { confirmDialog.style.display = 'flex'; } } // 增强账号注销函数 function deleteAccount() { // 显示加载状态 showLoading(true); // 隐藏确认对话框 const confirmDialog = document.getElementById('delete-confirm-dialog'); if (confirmDialog) { confirmDialog.style.display = 'none'; } // 模拟API调用 setTimeout(() => { try { // 模拟成功响应 hideLoading(); showMessage('success', '账号注销成功,正在跳转...'); // 清除认证数据 clearAuthData(); // 跳转回登录页面(假设登录页面是login.html) setTimeout(() => { window.location.href = 'login.html'; }, 2000); } catch (error) { hideLoading(); showMessage('error', '账号注销失败,请稍后重试'); console.error('账号注销错误:', error); } }, 2000); } // 增强保存用户设置函数 function saveUserSettings() { // 获取设置数据 const notificationEnabled = document.getElementById('notification-enabled').checked; const theme = document.getElementById('theme-select').value; const language = document.getElementById('language-select').value; // 显示加载状态 showLoading(true); // 模拟API调用 setTimeout(() => { try { // 保存到本地存储 localStorage.setItem('userTheme', theme); localStorage.setItem('userLanguage', language); localStorage.setItem('notificationsEnabled', notificationEnabled.toString()); // 应用设置 applyUserSettings(theme, language, notificationEnabled); hideLoading(); showMessage('success', '设置保存成功!'); } catch (error) { hideLoading(); showMessage('error', '设置保存失败,请稍后重试'); console.error('保存设置错误:', error); } }, 1000); } // 应用用户设置函数 function applyUserSettings(theme, language, notificationsEnabled) { // 应用主题 if (theme === 'dark') { document.body.classList.add('dark-theme'); document.body.classList.remove('light-theme'); } else { document.body.classList.add('light-theme'); document.body.classList.remove('dark-theme'); } // 这里可以添加语言切换逻辑 // ... showMessage('info', `已应用设置: 主题=${theme}, 语言=${language}, 通知=${notificationsEnabled ? '开启' : '关闭'}`); } // 增强页面加载时的初始化 window.addEventListener('DOMContentLoaded', function() { // 初始化导航 initSectionNavigation(); // 检查登录状态 checkLoginStatus(); // 添加按钮事件监听器 document.getElementById('delete-account-btn').addEventListener('click', showDeleteAccountConfirm); document.getElementById('save-settings-btn').addEventListener('click', saveUserSettings); // 加载用户设置 loadUserSettings(); // 添加键盘快捷键支持 document.addEventListener('keydown', function(e) { // ESC键关闭对话框 if (e.key === 'Escape') { const dialog = document.getElementById('delete-confirm-dialog'); if (dialog && dialog.style.display !== 'none') { dialog.style.display = 'none'; } } }); }); // 添加消息提示的CSS样式 /* 消息提示样式 */ .message-toast { position: fixed; top: 20px; right: -400px; padding: 12px 24px; border-radius: 4px; color: white; font-size: 14px; font-weight: 500; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); z-index: 10000; transition: right 0.3s ease; max-width: 350px; } .message-toast.show { right: 20px; } .message-success { background-color: #52c41a; } .message-error { background-color: #ff4d4f; } .message-info { background-color: #1890ff; } .message-warning { background-color: #faad14; } /* 增强密码强度指示器样式 */ .password-strength-container { margin-top: 10px; } .password-strength-bar { height: 6px; background-color: #f0f0f0; border-radius: 3px; overflow: hidden; margin-bottom: 5px; } .strength-bar { height: 100%; width: 0; transition: width 0.3s ease, background-color 0.3s ease; } .strength-bar.weak { background-color: #ff4d4f; } .strength-bar.weak-medium { background-color: #faad14; } .strength-bar.medium { background-color: #fa8c16; } .strength-bar.strong-medium { background-color: #52c41a; } .strength-bar.strong { background-color: #1890ff; } .strength-text { font-size: 12px; margin-bottom: 8px; } .strength-text.weak { color: #ff4d4f; } .strength-text.weak-medium { color: #faad14; } .strength-text.medium { color: #fa8c16; } .strength-text.strong-medium { color: #52c41a; } .strength-text.strong { color: #1890ff; } .password-requirements { font-size: 12px; } .requirement { margin: 2px 0; color: #666; } .requirement.met { color: #52c41a; } .password-match-message { font-size: 12px; margin-top: 5px; } .password-match-message.match { color: #52c41a; } .password-match-message.mismatch { color: #ff4d4f; }