243 lines
9.2 KiB
JavaScript
243 lines
9.2 KiB
JavaScript
/**
|
|
* 学生端功能管理
|
|
*/
|
|
class StudentManager {
|
|
constructor() {
|
|
this.apiBase = '/api/student';
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.initDashboard();
|
|
this.initMyCourses();
|
|
this.updateCurrentTime();
|
|
setInterval(() => this.updateCurrentTime(), 1000);
|
|
}
|
|
|
|
updateCurrentTime() {
|
|
const timeElement = document.getElementById('currentTime');
|
|
if (timeElement) {
|
|
const now = new Date();
|
|
const options = {
|
|
year: 'numeric', month: 'long', day: 'numeric',
|
|
hour: '2-digit', minute: '2-digit', second: '2-digit'
|
|
};
|
|
timeElement.textContent = now.toLocaleString('zh-CN', options);
|
|
}
|
|
}
|
|
|
|
async initDashboard() {
|
|
// 检查是否在仪表板页面
|
|
if (!document.getElementById('gradesTableBody')) return;
|
|
|
|
try {
|
|
const response = await fetch(`${this.apiBase}/grades`);
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.renderDashboard(result.data);
|
|
} else {
|
|
if (window.authManager) {
|
|
window.authManager.showNotification(result.message || '获取数据失败', 'error');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch dashboard data failed:', error);
|
|
}
|
|
}
|
|
|
|
async initMyCourses() {
|
|
// 检查是否在我的课程页面
|
|
const tbody = document.getElementById('coursesTableBody');
|
|
if (!tbody) return;
|
|
|
|
try {
|
|
const response = await fetch(`${this.apiBase}/courses`);
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.renderCourses(result.data);
|
|
} else {
|
|
if (window.authManager) {
|
|
window.authManager.showNotification(result.message || '获取课程失败', 'error');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch courses data failed:', error);
|
|
}
|
|
}
|
|
|
|
renderCourses(courses) {
|
|
const tbody = document.getElementById('coursesTableBody');
|
|
if (!tbody) return;
|
|
|
|
if (!courses || courses.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="6" class="text-center py-4 text-muted">暂无课程记录</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = courses.map(course => `
|
|
<tr>
|
|
<td>${course.course_code}</td>
|
|
<td>${course.course_name}</td>
|
|
<td>${course.credit}</td>
|
|
<td>${course.teacher_name}</td>
|
|
<td>${course.semester || '2023-2024 下学期'}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="studentManager.viewCourseDetails(${course.id})">
|
|
<i class="fas fa-info-circle"></i> 课程详情
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
|
|
async viewCourseDetails(courseId) {
|
|
try {
|
|
const response = await fetch(`${this.apiBase}/courses/${courseId}`);
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
const course = result.data;
|
|
this.updateElement('modalCourseName', course.course_name);
|
|
this.updateElement('modalCourseCode', course.course_code);
|
|
this.updateElement('modalCourseCredit', course.credit);
|
|
this.updateElement('modalTeacherName', course.teacher_name);
|
|
this.updateElement('modalClassName', course.class_name);
|
|
this.updateElement('modalSemester', course.semester || '2023-2024 下学期');
|
|
this.updateElement('modalTeacherEmail', course.teacher_email || '暂无');
|
|
|
|
const modal = new bootstrap.Modal(document.getElementById('courseDetailsModal'));
|
|
modal.show();
|
|
} else {
|
|
if (window.authManager) {
|
|
window.authManager.showNotification(result.message || '获取课程详情失败', 'error');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch course details failed:', error);
|
|
}
|
|
}
|
|
|
|
renderDashboard(data) {
|
|
const { grades, statistics } = data;
|
|
|
|
// 渲染统计数据
|
|
if (statistics) {
|
|
this.updateElement('gpaValue', statistics.gpa);
|
|
this.updateElement('courseCount', statistics.totalCourses);
|
|
this.updateElement('creditTotal', statistics.totalCredits);
|
|
// 班级排名如果后端没提供,可以显示为 '-' 或固定值
|
|
this.updateElement('classRank', statistics.classRank || '-');
|
|
}
|
|
|
|
// 渲染成绩表格
|
|
const tbody = document.getElementById('gradesTableBody');
|
|
if (tbody) {
|
|
if (!grades || grades.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="8" class="text-center py-4 text-muted">暂无成绩记录</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = grades.map(grade => `
|
|
<tr>
|
|
<td>${grade.course_name}</td>
|
|
<td>${grade.course_code || '-'}</td>
|
|
<td>${grade.credit}</td>
|
|
<td>${grade.score}</td>
|
|
<td>${grade.grade_level || '-'}</td>
|
|
<td>${grade.grade_point || '-'}</td>
|
|
<td>
|
|
<span class="badge ${this.getScoreBadgeClass(grade.score)}">
|
|
${this.getScoreText(grade.score)}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="studentManager.viewDetails(${grade.id})">
|
|
<i class="fas fa-eye"></i> 详情
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
}
|
|
|
|
updateElement(id, value) {
|
|
const el = document.getElementById(id);
|
|
if (el) el.textContent = value;
|
|
}
|
|
|
|
getScoreBadgeClass(score) {
|
|
const s = parseFloat(score);
|
|
if (s >= 90) return 'bg-success';
|
|
if (s >= 80) return 'bg-info';
|
|
if (s >= 60) return 'bg-warning';
|
|
return 'bg-danger';
|
|
}
|
|
|
|
getScoreText(score) {
|
|
const s = parseFloat(score);
|
|
if (s >= 60) return '及格';
|
|
return '不及格';
|
|
}
|
|
|
|
async viewDetails(id) {
|
|
try {
|
|
const response = await fetch(`${this.apiBase}/grades/${id}`);
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
const grade = result.data.grade;
|
|
this.updateElement('modalGradeCourseName', grade.course_name);
|
|
this.updateElement('modalGradeCourseCode', grade.course_code);
|
|
this.updateElement('modalTotalScore', grade.score);
|
|
this.updateElement('modalUsualScore', grade.usual_score || '-');
|
|
this.updateElement('modalMidtermScore', grade.midterm_score || '-');
|
|
this.updateElement('modalFinalScore', grade.final_score || '-');
|
|
this.updateElement('modalGradeCredit', grade.credit);
|
|
this.updateElement('modalGradeLevel', grade.grade_level || '-');
|
|
this.updateElement('modalGradePoint', grade.grade_point || '-');
|
|
this.updateElement('modalGradeTeacher', grade.teacher_name);
|
|
this.updateElement('modalGradeTime', new Date(grade.created_at).toLocaleString());
|
|
|
|
const remarkContainer = document.getElementById('modalRemarkContainer');
|
|
if (grade.remark) {
|
|
remarkContainer.style.display = 'block';
|
|
this.updateElement('modalRemark', grade.remark);
|
|
} else {
|
|
remarkContainer.style.display = 'none';
|
|
}
|
|
|
|
const modal = new bootstrap.Modal(document.getElementById('gradeDetailsModal'));
|
|
modal.show();
|
|
} else {
|
|
if (window.authManager) {
|
|
window.authManager.showNotification(result.message || '获取成绩详情失败', 'error');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch grade details failed:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 初始化
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.studentManager = new StudentManager();
|
|
|
|
// 从 Session 获取用户信息并更新 UI
|
|
fetch('/api/auth/me')
|
|
.then(res => res.json())
|
|
.then(result => {
|
|
if (result.success && result.data.user) {
|
|
const user = result.data.user;
|
|
const nameEl = document.getElementById('userName');
|
|
const studentNameEl = document.getElementById('studentName');
|
|
const studentClassEl = document.getElementById('studentClass');
|
|
|
|
if (nameEl) nameEl.textContent = user.name;
|
|
if (studentNameEl) studentNameEl.textContent = user.name;
|
|
if (studentClassEl) studentClassEl.textContent = user.class || '未分配';
|
|
}
|
|
});
|
|
}); |