Book_system/app/static/js/user-profile.js
superlishunqin 29009ef7de user
2025-05-01 04:52:53 +08:00

276 lines
9.3 KiB
JavaScript

// 用户个人中心页面交互
document.addEventListener('DOMContentLoaded', function() {
// 获取表单对象
const profileForm = document.getElementById('profileForm');
const passwordForm = document.getElementById('passwordForm');
// 表单验证逻辑
if (profileForm) {
profileForm.addEventListener('submit', function(event) {
let valid = true;
// 清除之前的错误提示
clearValidationErrors();
// 验证邮箱
const emailField = document.getElementById('email');
if (emailField.value.trim() !== '') {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailPattern.test(emailField.value.trim())) {
showError(emailField, '请输入有效的邮箱地址');
valid = false;
}
}
// 验证手机号
const phoneField = document.getElementById('phone');
if (phoneField.value.trim() !== '') {
const phonePattern = /^1[3456789]\d{9}$/;
if (!phonePattern.test(phoneField.value.trim())) {
showError(phoneField, '请输入有效的手机号码');
valid = false;
}
}
if (!valid) {
event.preventDefault();
}
});
}
// 密码修改表单验证
if (passwordForm) {
passwordForm.addEventListener('submit', function(event) {
let valid = true;
// 清除之前的错误提示
clearValidationErrors();
// 验证当前密码
const currentPasswordField = document.getElementById('current_password');
if (currentPasswordField.value.trim() === '') {
showError(currentPasswordField, '请输入当前密码');
valid = false;
}
// 验证新密码
const newPasswordField = document.getElementById('new_password');
if (newPasswordField.value.trim() === '') {
showError(newPasswordField, '请输入新密码');
valid = false;
} else if (newPasswordField.value.length < 6) {
showError(newPasswordField, '密码长度至少为6个字符');
valid = false;
}
// 验证确认密码
const confirmPasswordField = document.getElementById('confirm_password');
if (confirmPasswordField.value.trim() === '') {
showError(confirmPasswordField, '请确认新密码');
valid = false;
} else if (confirmPasswordField.value !== newPasswordField.value) {
showError(confirmPasswordField, '两次输入的密码不一致');
valid = false;
}
if (!valid) {
event.preventDefault();
}
});
}
// 获取用户统计数据
fetchUserStats();
// 获取用户活动记录
const activityFilter = document.getElementById('activityFilter');
if (activityFilter) {
// 初始加载
fetchUserActivities('all');
// 监听过滤器变化
activityFilter.addEventListener('change', function() {
fetchUserActivities(this.value);
});
}
// 处理URL中的tab参数
const urlParams = new URLSearchParams(window.location.search);
const tabParam = urlParams.get('tab');
if (tabParam) {
const tabElement = document.getElementById(`${tabParam}-tab`);
if (tabElement) {
$('#profileTabs a[href="#' + tabParam + '"]').tab('show');
}
}
// 清除表单验证错误
function clearValidationErrors() {
const invalidFields = document.querySelectorAll('.is-invalid');
const feedbackElements = document.querySelectorAll('.invalid-feedback');
invalidFields.forEach(field => {
field.classList.remove('is-invalid');
});
feedbackElements.forEach(element => {
element.parentNode.removeChild(element);
});
}
// 显示错误消息
function showError(field, message) {
field.classList.add('is-invalid');
const feedback = document.createElement('div');
feedback.className = 'invalid-feedback';
feedback.innerText = message;
field.parentNode.appendChild(feedback);
}
// 获取用户统计数据
function fetchUserStats() {
// 这里使用虚拟数据,实际应用中应当从后端获取
// fetch('/api/user/stats')
// .then(response => response.json())
// .then(data => {
// updateUserStats(data);
// });
// 模拟数据
setTimeout(() => {
const mockData = {
borrow: 2,
returned: 15,
overdue: 0
};
updateUserStats(mockData);
}, 500);
}
// 更新用户统计显示
function updateUserStats(data) {
const borrowCount = document.getElementById('borrowCount');
const returnedCount = document.getElementById('returnedCount');
const overdueCount = document.getElementById('overdueCount');
if (borrowCount) borrowCount.textContent = data.borrow;
if (returnedCount) returnedCount.textContent = data.returned;
if (overdueCount) overdueCount.textContent = data.overdue;
}
// 获取用户活动记录
function fetchUserActivities(type) {
const timelineContainer = document.getElementById('activityTimeline');
if (!timelineContainer) return;
// 显示加载中
timelineContainer.innerHTML = `
<div class="timeline-loading">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<p>加载中...</p>
</div>
`;
// 实际应用中应当从后端获取
// fetch(`/api/user/activities?type=${type}`)
// .then(response => response.json())
// .then(data => {
// renderActivityTimeline(data, timelineContainer);
// });
// 模拟数据
setTimeout(() => {
const mockActivities = [
{
id: 1,
type: 'login',
title: '系统登录',
details: '成功登录系统',
time: '2023-04-28 15:30:22',
ip: '192.168.1.1'
},
{
id: 2,
type: 'borrow',
title: '借阅图书',
details: '借阅《JavaScript高级编程》',
time: '2023-04-27 11:45:10',
book_id: 101
},
{
id: 3,
type: 'return',
title: '归还图书',
details: '归还《Python数据分析》',
time: '2023-04-26 09:15:33',
book_id: 95
},
{
id: 4,
type: 'login',
title: '系统登录',
details: '成功登录系统',
time: '2023-04-25 08:22:15',
ip: '192.168.1.1'
}
];
// 根据筛选条件过滤活动
let filteredActivities = mockActivities;
if (type !== 'all') {
filteredActivities = mockActivities.filter(activity => activity.type === type);
}
renderActivityTimeline(filteredActivities, timelineContainer);
}, 800);
}
// 渲染活动时间线
function renderActivityTimeline(activities, container) {
if (!activities || activities.length === 0) {
container.innerHTML = '<div class="text-center p-4">暂无活动记录</div>';
return;
}
let timelineHTML = '';
activities.forEach((activity, index) => {
let iconClass = 'fas fa-info';
if (activity.type === 'login') {
iconClass = 'fas fa-sign-in-alt';
} else if (activity.type === 'borrow') {
iconClass = 'fas fa-book';
} else if (activity.type === 'return') {
iconClass = 'fas fa-undo';
}
const isLast = index === activities.length - 1;
timelineHTML += `
<div class="timeline-item ${isLast ? 'last' : ''} timeline-type-${activity.type}">
<div class="timeline-icon">
<i class="${iconClass}"></i>
</div>
<div class="timeline-content">
<div class="timeline-header">
<h5 class="timeline-title">${activity.title}</h5>
<div class="timeline-time">${activity.time}</div>
</div>
<div class="timeline-details">
${activity.details}
${activity.ip ? `<div class="text-muted small">IP: ${activity.ip}</div>` : ''}
</div>
</div>
</div>
`;
});
container.innerHTML = timelineHTML;
}
});