first commit

This commit is contained in:
祀梦
2025-12-21 21:50:37 +08:00
commit 352698044b
30 changed files with 9893 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
const mysql = require('mysql2/promise');
require('dotenv').config();
const pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '123456',
database: process.env.DB_NAME || 'score_management',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// 测试数据库连接
async function testConnection() {
try {
const connection = await pool.getConnection();
console.log('数据库连接成功');
connection.release();
return true;
} catch (error) {
console.error('数据库连接失败:', error.message);
return false;
}
}
// 执行查询
async function query(sql, params) {
try {
const [rows] = await pool.execute(sql, params);
return rows;
} catch (error) {
console.error('数据库查询错误:', error.message);
throw error;
}
}
// 执行事务
async function executeTransaction(operations) {
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
for (const operation of operations) {
await connection.execute(operation.sql, operation.params);
}
await connection.commit();
console.log('事务执行成功');
} catch (error) {
await connection.rollback();
console.error('事务执行失败:', error.message);
throw error;
} finally {
connection.release();
}
}
module.exports = {
pool,
query,
executeTransaction,
testConnection
};

170
backend/middleware/auth.js Normal file
View File

@@ -0,0 +1,170 @@
const db = require('../config/database');
/**
* 认证中间件 - 检查用户是否已登录
*/
const requireAuth = (req, res, next) => {
if (!req.session.user) {
return res.status(401).json({
success: false,
message: '请先登录'
});
}
next();
};
/**
* 角色权限中间件 - 检查用户是否具有指定角色
* @param {Array} allowedRoles - 允许的角色数组
*/
const requireRole = (allowedRoles) => {
return (req, res, next) => {
if (!req.session.user) {
return res.status(401).json({
success: false,
message: '请先登录'
});
}
const userRole = req.session.user.role;
if (!allowedRoles.includes(userRole)) {
return res.status(403).json({
success: false,
message: '权限不足'
});
}
next();
};
};
/**
* 获取当前用户ID
*/
const getCurrentUserId = (req) => {
return req.session.user ? req.session.user.id : null;
};
/**
* 获取当前用户角色
*/
const getCurrentUserRole = (req) => {
return req.session.user ? req.session.user.role : null;
};
/**
* 检查是否是自己的数据(学生只能访问自己的数据)
*/
const checkOwnership = async (req, res, next) => {
try {
const userId = getCurrentUserId(req);
const userRole = getCurrentUserRole(req);
// 管理员和教师可以访问所有数据
if (userRole === 'admin' || userRole === 'teacher') {
return next();
}
// 学生只能访问自己的数据
if (userRole === 'student') {
const studentId = req.params.studentId || req.body.studentId;
// 检查学生ID是否属于当前用户
const [students] = await db.execute(
'SELECT id FROM students WHERE user_id = ?',
[userId]
);
if (students.length === 0) {
return res.status(403).json({
success: false,
message: '未找到学生信息'
});
}
const userStudentId = students[0].id;
// 如果请求中没有指定学生ID默认使用当前用户的学生ID
if (!studentId) {
req.studentId = userStudentId;
return next();
}
// 检查请求的学生ID是否与当前用户的学生ID匹配
if (parseInt(studentId) !== userStudentId) {
return res.status(403).json({
success: false,
message: '无权访问其他学生的数据'
});
}
req.studentId = userStudentId;
return next();
}
// 其他角色无权访问
return res.status(403).json({
success: false,
message: '权限不足'
});
} catch (error) {
console.error('所有权检查错误:', error);
res.status(500).json({
success: false,
message: '服务器错误'
});
}
};
/**
* 输入验证中间件
*/
const validateInput = (schema) => {
return (req, res, next) => {
const { error } = schema.validate(req.body);
if (error) {
return res.status(400).json({
success: false,
message: error.details[0].message
});
}
next();
};
};
/**
* 日志记录中间件
*/
const logOperation = (operation) => {
return async (req, res, next) => {
try {
const userId = getCurrentUserId(req);
const userRole = getCurrentUserRole(req);
const ip = req.ip || req.connection.remoteAddress;
// 记录操作日志
await db.execute(
'INSERT INTO operation_logs (user_id, operation, ip_address, user_role) VALUES (?, ?, ?, ?)',
[userId, operation, ip, userRole]
);
next();
} catch (error) {
console.error('日志记录错误:', error);
// 日志记录失败不影响主要操作
next();
}
};
};
module.exports = {
requireAuth,
requireRole,
getCurrentUserId,
getCurrentUserRole,
checkOwnership,
validateInput,
logOperation
};

1491
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
backend/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "grade-management-system",
"version": "1.0.0",
"description": "学生成绩管理系统后端",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5",
"express-session": "^1.17.3",
"express-mysql-session": "^3.0.0",
"mysql2": "^3.6.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.3.1",
"body-parser": "^1.20.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
},
"engines": {
"node": ">=14.0.0"
}
}

311
backend/routes/admin.js Normal file
View 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
View 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
View 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
View 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;

128
backend/server.js Normal file
View File

@@ -0,0 +1,128 @@
const express = require('express');
const cors = require('cors');
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
const path = require('path');
require('dotenv').config();
// 导入路由
const authRoutes = require('./routes/auth');
const studentRoutes = require('./routes/student');
const teacherRoutes = require('./routes/teacher');
const adminRoutes = require('./routes/admin');
// 数据库配置
const db = require('./config/database');
const app = express();
const PORT = process.env.PORT || 3000;
// 中间件
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 会话配置
const sessionStore = new MySQLStore({
expiration: 86400000, // 1天
createDatabaseTable: true,
schema: {
tableName: 'sessions',
columnNames: {
session_id: 'session_id',
expires: 'expires',
data: 'data'
}
}
}, db.pool);
app.use(session({
key: 'session_cookie',
secret: process.env.SESSION_SECRET || 'your-secret-key',
store: sessionStore,
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 86400000,
httpOnly: true,
secure: process.env.NODE_ENV === 'production'
}
}));
// 静态文件服务
app.use(express.static(path.join(__dirname, '../frontend')));
// 重定向旧路径 /frontend/html/* 到 /html/*
app.get('/frontend/html/*', (req, res) => {
const path = req.params[0];
res.redirect(`/html/${path}`);
});
// 路由
app.use('/api/auth', authRoutes);
app.use('/api/student', studentRoutes);
app.use('/api/teacher', teacherRoutes);
app.use('/api/admin', adminRoutes);
// 认证中间件
const { requireAuth, requireRole } = require('./middleware/auth');
// 页面路由
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../frontend/html/login.html'));
});
app.get('/dashboard', requireAuth, (req, res) => {
// 根据用户角色重定向到不同的仪表板
const role = req.session.user?.role;
switch (role) {
case 'student':
res.redirect('/html/student_dashboard.html');
break;
case 'teacher':
res.redirect('/html/teacher_dashboard.html');
break;
case 'admin':
res.redirect('/html/admin_dashboard.html');
break;
default:
// 如果没有角色信息,重定向到登录页面
res.redirect('/');
break;
}
});
// 学生页面路由
app.get('/student/*', requireAuth, requireRole(['student', 'admin', 'teacher']), (req, res, next) => {
next();
});
// 教师页面路由
app.get('/teacher/*', requireAuth, requireRole(['teacher', 'admin']), (req, res, next) => {
next();
});
// 管理员页面路由
app.get('/admin/*', requireAuth, requireRole(['admin']), (req, res, next) => {
next();
});
// 404处理
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});
// 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
console.log(`访问地址: http://localhost:${PORT}`);
});