Files
WebWork/frontend/public/js/main.js
祀梦 bcf2c71fad refactor(frontend): 重构前端目录结构并优化认证流程
将前端文件从html目录迁移到views目录,按功能模块组织
重构认证中间件和路由处理,简化页面权限控制
更新静态资源引用路径,统一使用/public前缀
添加学生仪表板页面,优化移动端显示
移除旧版html和js文件,更新样式和脚本
2025-12-21 22:07:23 +08:00

214 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

// é¦é¡µé€šç”¨JavaScript功能
// 主è¦<C3A8>处ç<E2809E>†å¯¼èˆªæ <C3A6>交äºã€<C3A3>页é<C2B5>¢æ»šåŠ¨æ•ˆæžœç­‰é€šç”¨åŠŸèƒ½
class MainPage {
constructor() {
this.init();
}
init() {
// åˆ<C3A5>å§åŒæ‰€æœ‰åŠŸèƒ? this.initNavbar();
this.initScrollEffects();
this.initSmoothScroll();
this.initBackToTop();
this.initMobileMenu();
this.initAuthButtons();
}
// åˆ<C3A5>å§åŒå¯¼èˆªæ <C3A6>交äº
initNavbar() {
const navbar = document.querySelector('.navbar');
if (!navbar) return;
// 滚动时改å<C2B9>˜å¯¼èˆªæ <C3A6>æ ·å¼<C3A5>
window.addEventListener('scroll', () => {
if (window.scrollY > 50) {
navbar.classList.add('navbar-scrolled');
} else {
navbar.classList.remove('navbar-scrolled');
}
});
// åˆ<C3A5>å§åŒå½“å‰<C3A5>页é<C2B5>¢é«˜äº? this.highlightCurrentPage();
}
// 高亮当å‰<C3A5>页é<C2B5>¢å¯¼èˆªé“¾æŽ¥
highlightCurrentPage() {
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href && currentPath.includes(href.replace('.html', ''))) {
link.classList.add('active');
}
});
}
// åˆ<C3A5>å§åŒæ»šåŠ¨æ•ˆæž? initScrollEffects() {
// 滚动时显ç¤?éš<C3A9>è—<C3A8>元素
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
}
});
}, observerOptions);
// è§å¯Ÿéœ€è¦<C3A8>动画的元素
document.querySelectorAll('.feature-card, .hero-content').forEach(el => {
observer.observe(el);
});
}
// åˆ<C3A5>å§åŒå¹³æ»æ»šåŠ? initSmoothScroll() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
e.preventDefault();
const targetId = anchor.getAttribute('href');
if (targetId === '#') return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
}
// åˆ<C3A5>å§åŒè¿”åžé¡¶éƒ¨æŒ‰é? initBackToTop() {
const backToTopBtn = document.createElement('button');
backToTopBtn.id = 'backToTop';
backToTopBtn.innerHTML = '<i class="fas fa-chevron-up"></i>';
backToTopBtn.title = '返回顶部';
document.body.appendChild(backToTopBtn);
// 滚动时显ç¤?éš<C3A9>è—<C3A8>按é®
window.addEventListener('scroll', () => {
if (window.scrollY > 300) {
backToTopBtn.classList.add('show');
} else {
backToTopBtn.classList.remove('show');
}
});
// 点击返回顶部
backToTopBtn.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
}
// åˆ<C3A5>å§åŒç§»åŠ¨ç«¯è<C2AF>œå<C593>
initMobileMenu() {
const navbarToggler = document.querySelector('.navbar-toggler');
const navbarCollapse = document.querySelector('.navbar-collapse');
if (!navbarToggler || !navbarCollapse) return;
navbarToggler.addEventListener('click', () => {
navbarCollapse.classList.toggle('show');
});
// ç¹å‡»è<C2BB>œå<C593>•项å<C2B9>Žè‡ªåŠ¨å…³é—­ç§»åŠ¨è<C2A8>œå<C593>
document.querySelectorAll('.navbar-nav .nav-link').forEach(link => {
link.addEventListener('click', () => {
if (navbarCollapse.classList.contains('show')) {
navbarCollapse.classList.remove('show');
}
});
});
}
// åˆ<C3A5>å§åŒè®¤è¯<C3A8>按é®çжæ€? initAuthButtons() {
// 检查用户是å<C2AF>¦å·²ç™»å½•
this.checkLoginStatus().then(user => {
const loginBtn = document.getElementById('loginBtn');
const registerBtn = document.getElementById('registerBtn');
const heroLoginBtn = document.getElementById('heroLoginBtn');
if (user) {
// 用户已登录,显示仪表æ<C2A8>¿æŒ‰é? // æ ¹æ<C2B9>®ç”¨æˆ·è§è‰²è®¾ç½®æ­£ç¡®çš„仪表æ<C2A8>¿è·¯å¾„
let dashboardUrl = '/dashboard';
if (user.role === 'student') {
dashboardUrl = '/student/dashboard';
} else if (user.role === 'teacher') {
dashboardUrl = '/teacher/dashboard';
} else if (user.role === 'admin') {
dashboardUrl = '/admin/dashboard';
}
if (loginBtn) {
loginBtn.textContent = 'è¿å…¥ä»ªè¡¨æ<C2A8>?;
loginBtn.href = dashboardUrl;
}
if (heroLoginBtn) {
heroLoginBtn.textContent = 'è¿å¥ä»ªè¡¨æ<EFBFBD>?;
heroLoginBtn.href = dashboardUrl;
}
if (registerBtn) {
registerBtn.style.display = 'none';
}
}
});
}
// 检查登录状� async checkLoginStatus() {
try {
const apiBase = window.location.protocol === 'file:' ? 'http://localhost:3000/api' : '/api';
const response = await fetch(`${apiBase}/auth/me`);
const data = await response.json();
return data.success && data.user;
} catch (error) {
console.log('用户未登�);
return false;
}
}
// 显示通知
showNotification(message, type = 'info') {
// 创建通知元素
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="fas ${type === 'success' ? 'fa-check-circle' : type === 'error' ? 'fa-exclamation-circle' : 'fa-info-circle'}"></i>
<span>${message}</span>
</div>
`;
// 添加到页é<C2B5>? document.body.appendChild(notification);
// 显示通知
setTimeout(() => {
notification.classList.add('show');
}, 10);
// 自动éš<C3A9>è—<C3A8>
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 3000);
}
}
// 页é<C2B5>¢åŠ è½½å®Œæˆ<C3A6>å<EFBFBD>Žåˆ<C3A5>å§åŒ
document.addEventListener('DOMContentLoaded', () => {
new MainPage();
});