feat(学生): 添加学生课程查询功能
- 后端添加获取学生课程列表的API路由 - 实现Course模型中的findByStudentId方法查询学生课程 - 新增学生控制器的getCourses方法处理课程请求 - 前端添加课程表格展示及刷新功能
This commit is contained in:
@@ -30,6 +30,20 @@ class StudentController {
|
|||||||
error(res, '服务器错误');
|
error(res, '服务器错误');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getCourses(req, res) {
|
||||||
|
try {
|
||||||
|
const userId = req.session.user.id;
|
||||||
|
const data = await StudentService.getStudentCourses(userId);
|
||||||
|
success(res, data);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message === '学生信息不存在') {
|
||||||
|
return error(res, err.message, 404);
|
||||||
|
}
|
||||||
|
console.error('Get Courses Error:', err);
|
||||||
|
error(res, '服务器错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = StudentController;
|
module.exports = StudentController;
|
||||||
@@ -12,6 +12,19 @@ class Course {
|
|||||||
const rows = await db.query('SELECT * FROM courses WHERE id = ?', [id]);
|
const rows = await db.query('SELECT * FROM courses WHERE id = ?', [id]);
|
||||||
return rows[0];
|
return rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async findByStudentId(studentId) {
|
||||||
|
const sql = `
|
||||||
|
SELECT c.*, u.name as teacher_name
|
||||||
|
FROM courses c
|
||||||
|
JOIN classes cl ON c.class_id = cl.id
|
||||||
|
JOIN students s ON cl.class_name = s.class
|
||||||
|
JOIN users u ON c.teacher_id = u.id
|
||||||
|
WHERE s.id = ?
|
||||||
|
ORDER BY c.course_code
|
||||||
|
`;
|
||||||
|
return await db.query(sql, [studentId]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Course;
|
module.exports = Course;
|
||||||
@@ -5,5 +5,6 @@ const { requireAuth, requireRole } = require('../middleware/auth');
|
|||||||
|
|
||||||
router.get('/grades', requireAuth, requireRole(['student']), StudentController.getGrades);
|
router.get('/grades', requireAuth, requireRole(['student']), StudentController.getGrades);
|
||||||
router.get('/grades/:id', requireAuth, requireRole(['student']), StudentController.getGradeDetails);
|
router.get('/grades/:id', requireAuth, requireRole(['student']), StudentController.getGradeDetails);
|
||||||
|
router.get('/courses', requireAuth, requireRole(['student']), StudentController.getCourses);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
const Score = require('../models/Score');
|
const Score = require('../models/Score');
|
||||||
const Student = require('../models/Student');
|
const Student = require('../models/Student');
|
||||||
|
const Course = require('../models/Course');
|
||||||
|
|
||||||
class StudentService {
|
class StudentService {
|
||||||
static async getStudentGrades(userId) {
|
static async getStudentGrades(userId) {
|
||||||
// 先通过 userId 获取 studentId
|
|
||||||
// 假设 users.id = students.id,或者通过 user_id 关联
|
|
||||||
// 根据之前的 authService,我们假设 users.id 就是 students.id
|
|
||||||
|
|
||||||
// 确认学生是否存在
|
// 确认学生是否存在
|
||||||
const student = await Student.findById(userId);
|
const student = await Student.findById(userId);
|
||||||
if (!student) {
|
if (!student) {
|
||||||
@@ -50,6 +47,14 @@ class StudentService {
|
|||||||
}
|
}
|
||||||
return grade;
|
return grade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getStudentCourses(userId) {
|
||||||
|
const student = await Student.findById(userId);
|
||||||
|
if (!student) {
|
||||||
|
throw new Error('学生信息不存在');
|
||||||
|
}
|
||||||
|
return await Course.findByStudentId(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = StudentService;
|
module.exports = StudentService;
|
||||||
|
|||||||
@@ -9,8 +9,15 @@ class StudentManager {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.initDashboard();
|
this.initDashboard();
|
||||||
|
this.initCourses();
|
||||||
this.updateCurrentTime();
|
this.updateCurrentTime();
|
||||||
setInterval(() => this.updateCurrentTime(), 1000);
|
setInterval(() => this.updateCurrentTime(), 1000);
|
||||||
|
|
||||||
|
// 绑定刷新按钮
|
||||||
|
const refreshBtn = document.getElementById('refreshCourses');
|
||||||
|
if (refreshBtn) {
|
||||||
|
refreshBtn.addEventListener('click', () => this.initCourses());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentTime() {
|
updateCurrentTime() {
|
||||||
@@ -44,6 +51,51 @@ class StudentManager {
|
|||||||
console.error('Fetch dashboard data failed:', error);
|
console.error('Fetch dashboard data failed:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initCourses() {
|
||||||
|
// 检查是否在仪表板页面
|
||||||
|
if (!document.getElementById('coursesTableBody')) 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 failed:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCourses(courses) {
|
||||||
|
const tbody = document.getElementById('coursesTableBody');
|
||||||
|
if (tbody) {
|
||||||
|
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><code>${course.course_code}</code></td>
|
||||||
|
<td class="fw-bold">${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-light border" onclick="studentManager.viewCourseDetails(${course.id})">
|
||||||
|
<i class="fas fa-info-circle text-primary"></i> 详情
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
renderDashboard(data) {
|
renderDashboard(data) {
|
||||||
const { grades, statistics } = data;
|
const { grades, statistics } = data;
|
||||||
@@ -88,6 +140,11 @@ class StudentManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewCourseDetails(id) {
|
||||||
|
console.log('View details for course:', id);
|
||||||
|
// 可以弹出一个模态框显示更多信息
|
||||||
|
}
|
||||||
|
|
||||||
updateElement(id, value) {
|
updateElement(id, value) {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if (el) el.textContent = value;
|
if (el) el.textContent = value;
|
||||||
@@ -132,4 +189,4 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (studentClassEl) studentClassEl.textContent = user.class || '未分配';
|
if (studentClassEl) studentClassEl.textContent = user.class || '未分配';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -337,6 +337,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 我的课程表格 -->
|
||||||
|
<div class="card card-table mb-4" id="courses-section">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 fw-bold"><i class="fas fa-book me-2 text-primary"></i>我的课程</h5>
|
||||||
|
<button class="btn btn-sm btn-outline-primary px-3" id="refreshCourses">
|
||||||
|
<i class="fas fa-sync-alt me-1"></i> 刷新
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>课程代码</th>
|
||||||
|
<th>课程名称</th>
|
||||||
|
<th>学分</th>
|
||||||
|
<th>授课教师</th>
|
||||||
|
<th>学期</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="coursesTableBody">
|
||||||
|
<!-- 数据将由 JavaScript 填充 -->
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center py-5 text-muted">
|
||||||
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||||
|
数据加载中...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 成绩表格 -->
|
<!-- 成绩表格 -->
|
||||||
<div class="card card-table" id="grades-section">
|
<div class="card card-table" id="grades-section">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user