feat: 实现成绩管理系统核心功能
添加响应工具、错误处理中间件和数据库模型 创建用户、学生、课程和成绩相关服务 实现管理员、教师和学生控制器的基本功能 重构路由处理并优化数据库查询
This commit is contained in:
60
backend/services/adminService.js
Normal file
60
backend/services/adminService.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const db = require('../config/database');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const User = require('../models/User');
|
||||
|
||||
class AdminService {
|
||||
static async getUsers(params) {
|
||||
const { page = 1, limit = 10, search = '', role = '' } = params;
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
let queryStr = 'SELECT id, name, role, class, created_at FROM users WHERE 1=1';
|
||||
let queryParams = [];
|
||||
|
||||
if (search) {
|
||||
queryStr += ' AND (id LIKE ? OR name LIKE ? OR class LIKE ?)';
|
||||
const searchTerm = `%${search}%`;
|
||||
queryParams.push(searchTerm, searchTerm, searchTerm);
|
||||
}
|
||||
|
||||
if (role) {
|
||||
queryStr += ' AND role = ?';
|
||||
queryParams.push(role);
|
||||
}
|
||||
|
||||
// Count
|
||||
const countSql = queryStr.replace('SELECT id, name, role, class, created_at', 'SELECT COUNT(*) as total');
|
||||
const countRows = await db.query(countSql, queryParams);
|
||||
const total = countRows[0].total;
|
||||
|
||||
// Data
|
||||
queryStr += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
||||
queryParams.push(parseInt(limit), parseInt(offset));
|
||||
|
||||
const users = await db.query(queryStr, queryParams);
|
||||
|
||||
return {
|
||||
data: users,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total,
|
||||
pages: Math.ceil(total / limit)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static async createUser(userData) {
|
||||
const { id } = userData;
|
||||
|
||||
// 检查 ID
|
||||
const existingUser = await User.findById(id);
|
||||
if (existingUser) {
|
||||
throw new Error('用户ID已存在');
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
return await User.create(userData);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AdminService;
|
||||
61
backend/services/authService.js
Normal file
61
backend/services/authService.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const User = require('../models/User');
|
||||
const Student = require('../models/Student');
|
||||
|
||||
class AuthService {
|
||||
static async login(id, password, role) {
|
||||
const user = await User.findByIdAndRole(id, role);
|
||||
if (!user) {
|
||||
throw new Error('用户名或密码错误');
|
||||
}
|
||||
|
||||
const isValid = await User.verifyPassword(password, user.password);
|
||||
if (!isValid) {
|
||||
throw new Error('用户名或密码错误');
|
||||
}
|
||||
|
||||
const sessionUser = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
class: user.class
|
||||
};
|
||||
|
||||
if (user.role === 'student') {
|
||||
const studentInfo = await Student.findById(user.id); // 这里的 id 既是 users.id 也是 students.id
|
||||
if (studentInfo) {
|
||||
sessionUser.studentInfo = studentInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return sessionUser;
|
||||
}
|
||||
|
||||
static async register(userData) {
|
||||
const { id, role, class: userClass } = userData;
|
||||
|
||||
// 检查是否存在
|
||||
const existingUser = await User.findById(id);
|
||||
if (existingUser) {
|
||||
throw new Error('用户ID已存在');
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
const newUser = await User.create(userData);
|
||||
|
||||
// 如果是学生,需要同步创建 students 表记录
|
||||
// 注意:目前的逻辑好像混淆了 users.id 和 students.id,根据之前的 SQL,students.id 是主键且外键关联 users.id
|
||||
// 我们假设 users.id 就是学号
|
||||
if (role === 'student') {
|
||||
// 需要确保 students 表结构匹配
|
||||
await db.query(
|
||||
'INSERT INTO students (id, name, class) VALUES (?, ?, ?)',
|
||||
[id, userData.name, userClass]
|
||||
);
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
|
||||
const db = require('../config/database'); // 补充引用
|
||||
module.exports = AuthService;
|
||||
55
backend/services/studentService.js
Normal file
55
backend/services/studentService.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const Score = require('../models/Score');
|
||||
const Student = require('../models/Student');
|
||||
|
||||
class StudentService {
|
||||
static async getStudentGrades(userId) {
|
||||
// 先通过 userId 获取 studentId
|
||||
// 假设 users.id = students.id,或者通过 user_id 关联
|
||||
// 根据之前的 authService,我们假设 users.id 就是 students.id
|
||||
|
||||
// 确认学生是否存在
|
||||
const student = await Student.findById(userId);
|
||||
if (!student) {
|
||||
throw new Error('学生信息不存在');
|
||||
}
|
||||
|
||||
const grades = await Score.findByStudentId(userId);
|
||||
|
||||
// 计算统计信息
|
||||
let totalCredits = 0;
|
||||
let totalGradePoints = 0;
|
||||
const totalCourses = grades.length;
|
||||
|
||||
grades.forEach(grade => {
|
||||
const credit = parseFloat(grade.credit);
|
||||
totalCredits += credit;
|
||||
if (grade.grade_point) {
|
||||
totalGradePoints += parseFloat(grade.grade_point) * credit;
|
||||
}
|
||||
});
|
||||
|
||||
const gpa = totalCredits > 0 ? (totalGradePoints / totalCredits).toFixed(2) : 0;
|
||||
const averageScore = totalCourses > 0 ?
|
||||
(grades.reduce((sum, g) => sum + parseFloat(g.score || 0), 0) / totalCourses).toFixed(1) : 0;
|
||||
|
||||
return {
|
||||
grades,
|
||||
statistics: {
|
||||
totalCourses,
|
||||
totalCredits,
|
||||
gpa,
|
||||
averageScore
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static async getGradeDetails(scoreId, userId) {
|
||||
const grade = await Score.findDetailsById(scoreId, userId);
|
||||
if (!grade) {
|
||||
throw new Error('成绩不存在');
|
||||
}
|
||||
return grade;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StudentService;
|
||||
50
backend/services/teacherService.js
Normal file
50
backend/services/teacherService.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const Course = require('../models/Course');
|
||||
const Score = require('../models/Score');
|
||||
const Student = require('../models/Student');
|
||||
|
||||
class TeacherService {
|
||||
static async getCourses(teacherId) {
|
||||
return await Course.findByTeacherId(teacherId);
|
||||
}
|
||||
|
||||
static async addScore(teacherId, scoreData) {
|
||||
const { studentId, courseId, score } = scoreData;
|
||||
|
||||
// 验证学生
|
||||
const student = await Student.findById(studentId);
|
||||
if (!student) {
|
||||
throw new Error('学生不存在');
|
||||
}
|
||||
|
||||
// 验证课程(可选:验证是否是该教师的课程)
|
||||
// const course = await Course.findById(courseId);
|
||||
|
||||
// 检查重复
|
||||
const existingScore = await Score.findByStudentAndCourse(studentId, courseId);
|
||||
if (existingScore) {
|
||||
throw new Error('该学生此课程成绩已存在');
|
||||
}
|
||||
|
||||
// 计算绩点和等级
|
||||
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 fullScoreData = {
|
||||
...scoreData,
|
||||
teacherId,
|
||||
gradePoint,
|
||||
gradeLevel
|
||||
};
|
||||
|
||||
const gradeId = await Score.create(fullScoreData);
|
||||
return gradeId;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TeacherService;
|
||||
Reference in New Issue
Block a user