first commit
This commit is contained in:
311
backend/routes/admin.js
Normal file
311
backend/routes/admin.js
Normal file
@@ -0,0 +1,311 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../config/database');
|
||||
const { requireAuth, requireRole } = require('../middleware/auth');
|
||||
|
||||
/**
|
||||
* 获取所有用户
|
||||
*/
|
||||
router.get('/users', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const { page = 1, limit = 10, search = '', role = '' } = req.query;
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
let query = 'SELECT id, name, role, class, created_at FROM users WHERE 1=1';
|
||||
let params = [];
|
||||
|
||||
if (search) {
|
||||
query += ' AND (id LIKE ? OR name LIKE ? OR class LIKE ?)';
|
||||
const searchTerm = `%${search}%`;
|
||||
params.push(searchTerm, searchTerm, searchTerm);
|
||||
}
|
||||
|
||||
if (role) {
|
||||
query += ' AND role = ?';
|
||||
params.push(role);
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
const countQuery = query.replace('SELECT id, name, role, class, created_at', 'SELECT COUNT(*) as total');
|
||||
const countResult = await db.pool.execute(countQuery, params);
|
||||
const total = countResult[0][0].total;
|
||||
|
||||
// 获取分页数据
|
||||
query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
||||
params.push(parseInt(limit), parseInt(offset));
|
||||
|
||||
const users = await db.pool.execute(query, params);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: users,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total,
|
||||
pages: Math.ceil(total / limit)
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取用户列表错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
router.post('/users', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const { id, name, password, role, className } = req.body;
|
||||
|
||||
// 输入验证
|
||||
if (!id || !name || !password || !role) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请填写所有必填字段'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户ID是否存在
|
||||
const existingUsers = await db.pool.execute(
|
||||
'SELECT id FROM users WHERE id = ?',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (existingUsers[0].length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '用户ID已存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 哈希密码
|
||||
const bcrypt = require('bcrypt');
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const passwordHash = await bcrypt.hash(password, salt);
|
||||
|
||||
// 创建用户
|
||||
const result = await db.pool.execute(
|
||||
'INSERT INTO users (id, name, password, role, class) VALUES (?, ?, ?, ?, ?)',
|
||||
[id, name, passwordHash, role, className || null]
|
||||
);
|
||||
|
||||
const userId = result[0].insertId;
|
||||
|
||||
// 根据角色创建相关记录
|
||||
if (role === 'student') {
|
||||
const studentId = 'STU' + Date.now().toString().slice(-6);
|
||||
await db.pool.execute(
|
||||
'INSERT INTO students (user_id, student_id, full_name, class_name) VALUES (?, ?, ?, ?)',
|
||||
[userId, studentId, fullName, className || '未分配班级']
|
||||
);
|
||||
} else if (role === 'teacher') {
|
||||
await db.pool.execute(
|
||||
'INSERT INTO teachers (user_id, full_name) VALUES (?, ?)',
|
||||
[userId, fullName]
|
||||
);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '用户创建成功',
|
||||
userId
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('创建用户错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
router.put('/users/:id', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
const { name, role, className } = req.body;
|
||||
|
||||
// 检查用户是否存在
|
||||
const users = await db.pool.execute(
|
||||
'SELECT * FROM users WHERE id = ?',
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (users[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '用户不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const oldRole = users[0][0].role;
|
||||
|
||||
// 更新用户信息
|
||||
await db.pool.execute(
|
||||
'UPDATE users SET name = ?, role = ?, class = ? WHERE id = ?',
|
||||
[name, role, className || null, userId]
|
||||
);
|
||||
|
||||
// 如果角色改变,更新相关记录
|
||||
if (oldRole !== role) {
|
||||
// 删除旧角色的记录
|
||||
if (oldRole === 'student') {
|
||||
await db.pool.execute('DELETE FROM students WHERE user_id = ?', [userId]);
|
||||
} else if (oldRole === 'teacher') {
|
||||
await db.pool.execute('DELETE FROM teachers WHERE user_id = ?', [userId]);
|
||||
}
|
||||
|
||||
// 创建新角色的记录
|
||||
if (role === 'student') {
|
||||
await db.pool.execute(
|
||||
'INSERT INTO students (user_id, class) VALUES (?, ?)',
|
||||
[userId, className || null]
|
||||
);
|
||||
} else if (role === 'teacher') {
|
||||
// 教师不需要额外表
|
||||
}
|
||||
} else if (role === 'student' && className) {
|
||||
// 如果是学生且班级有变化,更新班级
|
||||
await db.pool.execute(
|
||||
'UPDATE students SET class = ? WHERE user_id = ?',
|
||||
[className, userId]
|
||||
);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '用户更新成功'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新用户错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
router.delete('/users/:id', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
|
||||
// 检查用户是否存在
|
||||
const users = await db.pool.execute(
|
||||
'SELECT role FROM users WHERE id = ?',
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (users[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '用户不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const userRole = users[0][0].role;
|
||||
|
||||
// 删除相关记录
|
||||
if (userRole === 'student') {
|
||||
await db.pool.execute('DELETE FROM students WHERE user_id = ?', [userId]);
|
||||
} else if (userRole === 'teacher') {
|
||||
await db.pool.execute('DELETE FROM teachers WHERE user_id = ?', [userId]);
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
await db.pool.execute('DELETE FROM users WHERE id = ?', [userId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '用户删除成功'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('删除用户错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取所有班级
|
||||
*/
|
||||
router.get('/classes', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const classes = await db.pool.execute(
|
||||
'SELECT DISTINCT class_name FROM students ORDER BY class_name'
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: classes
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取班级列表错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
*/
|
||||
router.get('/stats', requireAuth, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
// 用户统计
|
||||
const userStats = await db.pool.execute(
|
||||
'SELECT role, COUNT(*) as count FROM users GROUP BY role'
|
||||
);
|
||||
|
||||
// 班级统计
|
||||
const classStats = await db.pool.execute(
|
||||
'SELECT class_name, COUNT(*) as count FROM students GROUP BY class_name'
|
||||
);
|
||||
|
||||
// 课程统计
|
||||
const courseStats = await db.pool.execute(
|
||||
'SELECT COUNT(*) as total_courses FROM courses'
|
||||
);
|
||||
|
||||
// 成绩统计
|
||||
const gradeStats = await db.pool.execute(
|
||||
'SELECT COUNT(*) as total_grades FROM scores'
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
users: userStats[0],
|
||||
classes: classStats[0],
|
||||
total_courses: courseStats[0][0].total_courses,
|
||||
total_grades: gradeStats[0][0].total_grades
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取统计数据错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
175
backend/routes/auth.js
Normal file
175
backend/routes/auth.js
Normal file
@@ -0,0 +1,175 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const router = express.Router();
|
||||
const db = require('../config/database');
|
||||
|
||||
// 登录
|
||||
router.post('/login', async (req, res) => {
|
||||
try {
|
||||
const { id, password, role } = req.body;
|
||||
|
||||
// 输入验证
|
||||
if (!id || !password || !role) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请输入完整的登录信息'
|
||||
});
|
||||
}
|
||||
|
||||
// 查询用户
|
||||
const users = await db.query(
|
||||
'SELECT * FROM users WHERE id = ? AND role = ?',
|
||||
[id, role]
|
||||
);
|
||||
|
||||
if (users.length === 0) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '用户名或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
|
||||
// 验证密码
|
||||
const isValidPassword = await bcrypt.compare(password, user.password);
|
||||
if (!isValidPassword) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '用户名或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
// 设置会话
|
||||
req.session.user = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
class: user.class
|
||||
};
|
||||
|
||||
// 如果是学生,获取学生信息
|
||||
if (user.role === 'student') {
|
||||
const [students] = await db.pool.execute(
|
||||
'SELECT * FROM students WHERE id = ?',
|
||||
[user.id]
|
||||
);
|
||||
if (students[0].length > 0) {
|
||||
req.session.user.studentInfo = students[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '登录成功',
|
||||
user: req.session.user
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('登录错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 注册
|
||||
router.post('/register', async (req, res) => {
|
||||
try {
|
||||
const { id, name, password, role, class: userClass } = req.body;
|
||||
|
||||
// 输入验证
|
||||
if (!id || !name || !password || !role) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请填写所有必填字段(ID、姓名、密码、角色)'
|
||||
});
|
||||
}
|
||||
|
||||
// 学生和教师需要班级字段,管理员不需要
|
||||
if ((role === 'student' || role === 'teacher') && !userClass) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '学生和教师需要填写班级'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户ID是否存在
|
||||
const existingUsers = await db.query(
|
||||
'SELECT id FROM users WHERE id = ?',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (existingUsers.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '用户ID已存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 哈希密码
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const passwordHash = await bcrypt.hash(password, salt);
|
||||
|
||||
// 创建用户
|
||||
await db.pool.execute(
|
||||
'INSERT INTO users (id, name, password, role, class) VALUES (?, ?, ?, ?, ?)',
|
||||
[id, name, passwordHash, role, userClass || null]
|
||||
);
|
||||
|
||||
// 如果是学生,创建学生记录
|
||||
if (role === 'student') {
|
||||
await db.pool.execute(
|
||||
'INSERT INTO students (id, name, class) VALUES (?, ?, ?)',
|
||||
[id, name, userClass]
|
||||
);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '注册成功'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('注册错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 注销
|
||||
router.post('/logout', (req, res) => {
|
||||
req.session.destroy(err => {
|
||||
if (err) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '注销失败'
|
||||
});
|
||||
}
|
||||
res.clearCookie('session_cookie');
|
||||
res.json({
|
||||
success: true,
|
||||
message: '注销成功'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 获取当前用户信息
|
||||
router.get('/me', (req, res) => {
|
||||
if (!req.session.user) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '未登录'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
user: req.session.user
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
143
backend/routes/student.js
Normal file
143
backend/routes/student.js
Normal file
@@ -0,0 +1,143 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../config/database');
|
||||
const { requireAuth, requireRole } = require('../middleware/auth');
|
||||
|
||||
// 获取学生成绩
|
||||
router.get('/grades', requireAuth, requireRole(['student']), async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.user.id;
|
||||
|
||||
// 获取学生信息
|
||||
const students = await db.pool.execute(
|
||||
'SELECT id FROM students WHERE user_id = ?',
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (students[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '学生信息不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const studentId = students[0][0].id;
|
||||
|
||||
// 获取成绩信息
|
||||
const grades = await db.pool.execute(`
|
||||
SELECT s.*, c.course_code, c.course_name, c.credit,
|
||||
u.name as teacher_name
|
||||
FROM scores s
|
||||
JOIN courses c ON s.course_id = c.id
|
||||
JOIN users u ON s.teacher_id = u.id
|
||||
WHERE s.student_id = ?
|
||||
ORDER BY s.exam_date DESC
|
||||
`, [studentId]);
|
||||
|
||||
// 计算统计信息
|
||||
let totalCredits = 0;
|
||||
let totalGradePoints = 0;
|
||||
let totalCourses = grades.length;
|
||||
|
||||
grades.forEach(grade => {
|
||||
totalCredits += parseFloat(grade.credit);
|
||||
if (grade.grade_point) {
|
||||
totalGradePoints += parseFloat(grade.grade_point) * parseFloat(grade.credit);
|
||||
}
|
||||
});
|
||||
|
||||
const gpa = totalCredits > 0 ? (totalGradePoints / totalCredits).toFixed(2) : 0;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
grades,
|
||||
statistics: {
|
||||
totalCourses,
|
||||
totalCredits,
|
||||
gpa,
|
||||
averageScore: totalCourses > 0 ?
|
||||
(grades.reduce((sum, g) => sum + parseFloat(g.score || 0), 0) / totalCourses).toFixed(1) : 0
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取成绩错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取成绩详情
|
||||
router.get('/grades/:id', requireAuth, requireRole(['student']), async (req, res) => {
|
||||
try {
|
||||
const gradeId = req.params.id;
|
||||
const userId = req.session.user.id;
|
||||
|
||||
const grades = await db.pool.execute(`
|
||||
SELECT s.*, c.course_code, c.course_name, c.credit, c.semester,
|
||||
u.full_name as teacher_name, u.email as teacher_email,
|
||||
st.student_id as student_number, st.class_name, st.major
|
||||
FROM scores s
|
||||
JOIN courses c ON s.course_id = c.id
|
||||
JOIN users u ON s.teacher_id = u.id
|
||||
JOIN students st ON s.student_id = st.id
|
||||
WHERE s.id = ? AND st.user_id = ?
|
||||
`, [gradeId, userId]);
|
||||
|
||||
if (grades[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '成绩不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
grade: grades[0]
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取成绩详情错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取学生个人信息
|
||||
router.get('/profile', requireAuth, requireRole(['student']), async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.user.id;
|
||||
|
||||
const students = await db.pool.execute(`
|
||||
SELECT s.*, u.username, u.email, u.created_at as account_created
|
||||
FROM students s
|
||||
JOIN users u ON s.user_id = u.id
|
||||
WHERE u.id = ?
|
||||
`, [userId]);
|
||||
|
||||
if (students[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '学生信息不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
profile: students[0]
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取个人信息错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
243
backend/routes/teacher.js
Normal file
243
backend/routes/teacher.js
Normal file
@@ -0,0 +1,243 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../config/database');
|
||||
const { requireAuth, requireRole } = require('../middleware/auth');
|
||||
|
||||
// 获取教师教授的课程
|
||||
router.get('/courses', requireAuth, requireRole(['teacher']), async (req, res) => {
|
||||
try {
|
||||
const teacherId = req.session.user.id;
|
||||
|
||||
const courses = await db.pool.execute(
|
||||
'SELECT * FROM courses WHERE teacher_id = ? ORDER BY course_code',
|
||||
[teacherId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
courses
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取课程错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 录入成绩
|
||||
router.post('/grades', requireAuth, requireRole(['teacher']), async (req, res) => {
|
||||
try {
|
||||
const teacherId = req.session.user.id;
|
||||
const { studentId, courseId, score, examDate, remark } = req.body;
|
||||
|
||||
// 验证输入
|
||||
if (!studentId || !courseId || score === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请填写必填字段'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查学生和课程是否存在
|
||||
const students = await db.pool.execute(
|
||||
'SELECT id FROM students WHERE student_id = ?',
|
||||
[studentId]
|
||||
);
|
||||
|
||||
if (students[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '学生不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 计算绩点和等级
|
||||
const numericScore = parseFloat(score);
|
||||
let gradePoint = 0;
|
||||
let gradeLevel = 'F';
|
||||
|
||||
if (numericScore >= 90) {
|
||||
gradePoint = 4.0; gradeLevel = 'A';
|
||||
} else if (numericScore >= 80) {
|
||||
gradePoint = 3.0; gradeLevel = 'B';
|
||||
} else if (numericScore >= 70) {
|
||||
gradePoint = 2.0; gradeLevel = 'C';
|
||||
} else if (numericScore >= 60) {
|
||||
gradePoint = 1.0; gradeLevel = 'D';
|
||||
}
|
||||
|
||||
// 插入成绩
|
||||
const result = await db.pool.execute(
|
||||
`INSERT INTO scores (student_id, course_id, teacher_id, score,
|
||||
grade_point, grade_level, exam_date, remark)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[students[0][0].id, courseId, teacherId, numericScore,
|
||||
gradePoint, gradeLevel, examDate, remark]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '成绩录入成功',
|
||||
gradeId: result.insertId
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('录入成绩错误:', error);
|
||||
|
||||
// 处理唯一约束错误
|
||||
if (error.code === 'ER_DUP_ENTRY') {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '该学生此课程成绩已存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 查询成绩(按班级、课程)
|
||||
router.get('/grades', requireAuth, requireRole(['teacher']), async (req, res) => {
|
||||
try {
|
||||
const { class_name, course_id } = req.query;
|
||||
const teacherId = req.session.user.id;
|
||||
|
||||
let query = `
|
||||
SELECT sc.*, st.student_id, st.full_name, st.class_name,
|
||||
c.course_code, c.course_name, c.credit
|
||||
FROM scores sc
|
||||
JOIN students st ON sc.student_id = st.id
|
||||
JOIN courses c ON sc.course_id = c.id
|
||||
WHERE sc.teacher_id = ?
|
||||
`;
|
||||
|
||||
const params = [teacherId];
|
||||
|
||||
if (class_name) {
|
||||
query += ' AND st.class_name = ?';
|
||||
params.push(class_name);
|
||||
}
|
||||
|
||||
if (course_id) {
|
||||
query += ' AND sc.course_id = ?';
|
||||
params.push(course_id);
|
||||
}
|
||||
|
||||
query += ' ORDER BY st.class_name, st.student_id, sc.exam_date DESC';
|
||||
|
||||
const grades = await db.pool.execute(query, params);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
grades
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('查询成绩错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新成绩
|
||||
router.put('/grades/:id', requireAuth, requireRole(['teacher']), async (req, res) => {
|
||||
try {
|
||||
const gradeId = req.params.id;
|
||||
const teacherId = req.session.user.id;
|
||||
const { score, examDate, remark } = req.body;
|
||||
|
||||
// 验证成绩是否存在且属于该教师
|
||||
const existingGrades = await db.pool.execute(
|
||||
'SELECT id FROM scores WHERE id = ? AND teacher_id = ?',
|
||||
[gradeId, teacherId]
|
||||
);
|
||||
|
||||
if (existingGrades[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '成绩不存在或无权修改'
|
||||
});
|
||||
}
|
||||
|
||||
// 计算新的绩点和等级
|
||||
const numericScore = parseFloat(score);
|
||||
let gradePoint = 0;
|
||||
let gradeLevel = 'F';
|
||||
|
||||
if (numericScore >= 90) {
|
||||
gradePoint = 4.0; gradeLevel = 'A';
|
||||
} else if (numericScore >= 80) {
|
||||
gradePoint = 3.0; gradeLevel = 'B';
|
||||
} else if (numericScore >= 70) {
|
||||
gradePoint = 2.0; gradeLevel = 'C';
|
||||
} else if (numericScore >= 60) {
|
||||
gradePoint = 1.0; gradeLevel = 'D';
|
||||
}
|
||||
|
||||
// 更新成绩
|
||||
await db.pool.execute(
|
||||
`UPDATE scores SET score = ?, grade_point = ?, grade_level = ?,
|
||||
exam_date = ?, remark = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?`,
|
||||
[numericScore, gradePoint, gradeLevel, examDate, remark, gradeId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '成绩更新成功'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新成绩错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除成绩
|
||||
router.delete('/grades/:id', requireAuth, requireRole(['teacher']), async (req, res) => {
|
||||
try {
|
||||
const gradeId = req.params.id;
|
||||
const teacherId = req.session.user.id;
|
||||
|
||||
// 验证成绩是否存在且属于该教师
|
||||
const existingGrades = await db.pool.execute(
|
||||
'SELECT id FROM scores WHERE id = ? AND teacher_id = ?',
|
||||
[gradeId, teacherId]
|
||||
);
|
||||
|
||||
if (existingGrades[0].length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '成绩不存在或无权删除'
|
||||
});
|
||||
}
|
||||
|
||||
// 删除成绩
|
||||
await db.pool.execute('DELETE FROM scores WHERE id = ?', [gradeId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '成绩删除成功'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('删除成绩错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器错误'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user