class TeacherDashboard { constructor() { // 动态设置API基础URL,支持file:///协议和localhost:3000访问 this.apiBase = window.location.protocol === 'file:' ? 'http://localhost:3000/api' : '/api'; this.currentUser = null; this.courses = []; this.grades = []; this.init(); } async init() { // 检查登录状? if (!await this.checkAuth()) { window.location.href = '/login'; return; } // 加载用户信息 await this.loadUserInfo(); // 加载课程数据 await this.loadCourses(); // 加载成绩数据 await this.loadGrades(); // 绑定事件 this.bindEvents(); // 更新界面 this.updateUI(); } async checkAuth() { try { const response = await fetch(`${this.apiBase}/auth/check`, { credentials: 'include' }); if (!response.ok) { return false; } const data = await response.json(); return data.success && data.user.role === 'teacher'; } catch (error) { console.error('认证检查失?', error); return false; } } async loadUserInfo() { try { const response = await fetch(`${this.apiBase}/auth/me`, { credentials: 'include' }); if (response.ok) { const data = await response.json(); if (data.success) { this.currentUser = data.user; } } } catch (error) { console.error('加载用户信息失败:', error); } } async loadCourses() { try { const response = await fetch(`${this.apiBase}/teacher/courses`, { credentials: 'include' }); if (response.ok) { const data = await response.json(); if (data.success) { this.courses = data.courses; this.populateCourseSelectors(); } } } catch (error) { console.error('加载课程失败:', error); this.showNotification('加载课程失败', 'error'); } } async loadGrades(filters = {}) { try { const queryParams = new URLSearchParams(filters).toString(); const url = `${this.apiBase}/teacher/grades${queryParams ? '?' + queryParams : ''}`; const response = await fetch(url, { credentials: 'include' }); if (response.ok) { const data = await response.json(); if (data.success) { this.grades = data.grades; this.renderGradesTable(); } } } catch (error) { console.error('加载成绩失败:', error); this.showNotification('加载成绩失败', 'error'); } } populateCourseSelectors() { // 填充课程选择? const courseSelectors = document.querySelectorAll('.course-selector'); courseSelectors.forEach(select => { select.innerHTML = ''; this.courses.forEach(course => { const option = document.createElement('option'); option.value = course.id; option.textContent = `${course.course_code} - ${course.course_name}`; select.appendChild(option); }); }); } renderGradesTable() { const tableBody = document.getElementById('gradesTableBody'); if (!tableBody) return; if (this.grades.length === 0) { tableBody.innerHTML = `

暂无成绩数据

`; return; } tableBody.innerHTML = this.grades.map(grade => { const gradeClass = this.getGradeClass(grade.score); return ` ${grade.student_id} ${grade.full_name} ${grade.class_name} ${grade.course_code} ${grade.course_name} ${grade.score} ${grade.grade_level} ${grade.exam_date ? new Date(grade.exam_date).toLocaleDateString() : '未设?}
`; }).join(''); // 更新统计信息 this.updateStats(); } getGradeClass(score) { if (score >= 90) return 'grade-excellent'; if (score >= 80) return 'grade-good'; if (score >= 70) return 'grade-medium'; if (score >= 60) return 'grade-pass'; return 'grade-fail'; } updateStats() { if (this.grades.length === 0) return; const totalStudents = new Set(this.grades.map(g => g.student_id)).size; const avgScore = this.grades.reduce((sum, g) => sum + g.score, 0) / this.grades.length; const passRate = (this.grades.filter(g => g.score >= 60).length / this.grades.length * 100).toFixed(1); document.getElementById('totalStudents').textContent = totalStudents; document.getElementById('avgScore').textContent = avgScore.toFixed(1); document.getElementById('passRate').textContent = `${passRate}%`; } bindEvents() { // 搜索按钮 document.getElementById('searchBtn')?.addEventListener('click', () => { this.handleSearch(); }); // 重置按钮 document.getElementById('resetBtn')?.addEventListener('click', () => { this.resetFilters(); }); // 导出按钮 document.getElementById('exportBtn')?.addEventListener('click', () => { this.exportGrades(); }); // 批量删除按钮 document.getElementById('batchDeleteBtn')?.addEventListener('click', () => { this.batchDeleteGrades(); }); // 表格操作按钮事件委托 document.addEventListener('click', (e) => { if (e.target.closest('.btn-edit')) { const gradeId = e.target.closest('.btn-edit').dataset.id; this.editGrade(gradeId); } if (e.target.closest('.btn-delete')) { const gradeId = e.target.closest('.btn-delete').dataset.id; this.deleteGrade(gradeId); } }); // 退出登? document.getElementById('logoutBtn')?.addEventListener('click', () => { this.handleLogout(); }); } handleSearch() { const className = document.getElementById('classFilter')?.value || ''; const courseId = document.getElementById('courseFilter')?.value || ''; this.loadGrades({ class_name: className, course_id: courseId }); } resetFilters() { document.getElementById('classFilter').value = ''; document.getElementById('courseFilter').value = ''; this.loadGrades(); } async exportGrades() { try { const response = await fetch(`${this.apiBase}/teacher/grades/export`, { credentials: 'include' }); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `成绩报表_${new Date().toISOString().split('T')[0]}.xlsx`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } } catch (error) { console.error('导出失败:', error); this.showNotification('导出失败', 'error'); } } async batchDeleteGrades() { const checkboxes = document.querySelectorAll('.grade-checkbox:checked'); if (checkboxes.length === 0) { this.showNotification('请选择要删除的成绩', 'warning'); return; } if (!confirm(`确定要删除选中?${checkboxes.length} 条成绩记录吗?`)) { return; } const gradeIds = Array.from(checkboxes).map(cb => cb.dataset.id); try { const response = await fetch(`${this.apiBase}/teacher/grades/batch`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ gradeIds }) }); const data = await response.json(); if (data.success) { this.showNotification(`成功删除 ${gradeIds.length} 条成绩记录`, 'success'); await this.loadGrades(); } else { this.showNotification(data.message || '删除失败', 'error'); } } catch (error) { console.error('批量删除失败:', error); this.showNotification('批量删除失败', 'error'); } } async editGrade(gradeId) { const grade = this.grades.find(g => g.id == gradeId); if (!grade) return; // 这里可以打开编辑模态框 // 暂时使用简单提示框 const newScore = prompt('请输入新的分?', grade.score); if (newScore === null) return; const numericScore = parseFloat(newScore); if (isNaN(numericScore) || numericScore < 0 || numericScore > 100) { this.showNotification('请输?-100之间的有效分?, 'error'); return; } try { const response = await fetch(`${this.apiBase}/teacher/grades/${gradeId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ score: numericScore, examDate: grade.exam_date, remark: grade.remark }) }); const data = await response.json(); if (data.success) { this.showNotification('成绩更新成功', 'success'); await this.loadGrades(); } else { this.showNotification(data.message || '更新失败', 'error'); } } catch (error) { console.error('更新成绩失败:', error); this.showNotification('更新成绩失败', 'error'); } } async deleteGrade(gradeId) { if (!confirm('确定要删除这条成绩记录吗?)) { return; } try { const response = await fetch(`${this.apiBase}/teacher/grades/${gradeId}`, { method: 'DELETE', credentials: 'include' }); const data = await response.json(); if (data.success) { this.showNotification('成绩删除成功', 'success'); await this.loadGrades(); } else { this.showNotification(data.message || '删除失败', 'error'); } } catch (error) { console.error('删除成绩失败:', error); this.showNotification('删除成绩失败', 'error'); } } async handleLogout() { try { const response = await fetch(`${this.apiBase}/auth/logout`, { method: 'POST', credentials: 'include' }); if (response.ok) { window.location.href = '/login'; } } catch (error) { console.error('退出登录失?', error); } } updateUI() { // 更新用户信息 if (this.currentUser) { const userInfoElements = document.querySelectorAll('.user-info'); userInfoElements.forEach(el => { el.textContent = `${this.currentUser.full_name} (${this.currentUser.role})`; }); } } showNotification(message, type = 'info') { // 使用AuthManager的通知系统或简单alert if (typeof AuthManager !== 'undefined' && AuthManager.showNotification) { AuthManager.showNotification(message, type); } else { alert(`${type}: ${message}`); } } } // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', () => { if (window.location.pathname.includes('/teacher/')) { new TeacherDashboard(); } });