feat: 实现教师资料更新、操作日志和系统设置功能
新增教师资料更新功能,包括个人信息修改和密码更新 添加操作日志记录系统,记录用户关键操作 实现系统设置模块,支持动态配置系统参数 重构数据库模型,新增教师表和系统设置表 优化成绩录入逻辑,支持平时分、期中和期末成绩计算 添加数据导出功能,支持学生、教师和成绩数据导出 完善管理员后台,增加统计图表和操作日志查看
This commit is contained in:
@@ -2,10 +2,15 @@ const db = require('../config/database');
|
||||
|
||||
class Course {
|
||||
static async findByTeacherId(teacherId) {
|
||||
return await db.query(
|
||||
'SELECT * FROM courses WHERE teacher_id = ? ORDER BY course_code',
|
||||
[teacherId]
|
||||
);
|
||||
const sql = `
|
||||
SELECT c.*, cl.class_name,
|
||||
(SELECT COUNT(*) FROM students s WHERE s.class = cl.class_name) as student_count
|
||||
FROM courses c
|
||||
LEFT JOIN classes cl ON c.class_id = cl.id
|
||||
WHERE c.teacher_id = ?
|
||||
ORDER BY c.course_code
|
||||
`;
|
||||
return await db.query(sql, [teacherId]);
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
@@ -37,6 +42,28 @@ class Course {
|
||||
`;
|
||||
return await db.query(sql, [studentId]);
|
||||
}
|
||||
|
||||
static async getClasses() {
|
||||
return await db.query('SELECT * FROM classes');
|
||||
}
|
||||
|
||||
static async create(data) {
|
||||
const { course_name, course_code, credit, teacher_id, semester, class_id, category } = data;
|
||||
const sql = `INSERT INTO courses (course_name, course_code, credit, teacher_id, semester, class_id, category) VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
||||
const result = await db.query(sql, [course_name, course_code, credit, teacher_id, semester, class_id, category]);
|
||||
return result.insertId;
|
||||
}
|
||||
|
||||
static async update(id, data) {
|
||||
const { course_name, course_code, credit, semester, class_id } = data;
|
||||
const sql = `
|
||||
UPDATE courses
|
||||
SET course_name = ?, course_code = ?, credit = ?, semester = ?, class_id = ?
|
||||
WHERE id = ?
|
||||
`;
|
||||
const result = await db.query(sql, [course_name, course_code, credit, semester, class_id, id]);
|
||||
return result.affectedRows > 0;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Course;
|
||||
|
||||
28
backend/models/OperationLog.js
Normal file
28
backend/models/OperationLog.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const db = require('../config/database');
|
||||
|
||||
class OperationLog {
|
||||
static async add(logData) {
|
||||
const { user_id, type, target, description, ip } = logData;
|
||||
const sql = `
|
||||
INSERT INTO operation_logs (user_id, operation_type, operation_target, description, ip_address)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`;
|
||||
return await db.query(sql, [user_id, type, target, description, ip]);
|
||||
}
|
||||
|
||||
static async findAll(params = {}) {
|
||||
const limit = parseInt(params.limit) || 50;
|
||||
const offset = parseInt(params.offset) || 0;
|
||||
|
||||
const sql = `
|
||||
SELECT l.*, u.name as user_name
|
||||
FROM operation_logs l
|
||||
LEFT JOIN users u ON l.user_id = u.id
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
return await db.query(sql, [limit, offset]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OperationLog;
|
||||
@@ -41,7 +41,7 @@ class Score {
|
||||
const sql = `
|
||||
INSERT INTO grades (student_id, course_id, teacher_id, final_score, total_score,
|
||||
grade_point, grade_level, created_at, remark)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now', 'localtime'), ?)
|
||||
`;
|
||||
const result = await db.pool.execute(sql, [
|
||||
studentId, courseId, teacherId, score, score, gradePoint, gradeLevel, remark
|
||||
@@ -56,6 +56,78 @@ class Score {
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
static async findByTeacher(teacherId, filters) {
|
||||
let sql = `
|
||||
SELECT g.*, s.name as student_name, c.course_name
|
||||
FROM grades g
|
||||
JOIN students s ON g.student_id = s.id
|
||||
JOIN courses c ON g.course_id = c.id
|
||||
WHERE c.teacher_id = ?
|
||||
`;
|
||||
const params = [teacherId];
|
||||
|
||||
if (filters.courseId) {
|
||||
sql += ' AND g.course_id = ?';
|
||||
params.push(filters.courseId);
|
||||
}
|
||||
if (filters.studentName) {
|
||||
sql += ' AND (s.name LIKE ? OR s.id LIKE ?)';
|
||||
params.push(`%${filters.studentName}%`, `%${filters.studentName}%`);
|
||||
}
|
||||
return await db.query(sql, params);
|
||||
}
|
||||
|
||||
static async findCourseStudentsWithGrades(courseId, teacherId) {
|
||||
const sql = `
|
||||
SELECT s.id as student_id, s.name as student_name,
|
||||
g.usual_score, g.midterm_score, g.final_score, g.total_score, g.grade_point, g.grade_level,
|
||||
c.id as course_id, c.course_name
|
||||
FROM students s
|
||||
JOIN classes cl ON s.class = cl.class_name
|
||||
JOIN courses c ON c.class_id = cl.id
|
||||
LEFT JOIN grades g ON s.id = g.student_id AND g.course_id = c.id
|
||||
WHERE c.id = ? AND c.teacher_id = ?
|
||||
`;
|
||||
return await db.query(sql, [courseId, teacherId]);
|
||||
}
|
||||
|
||||
static async upsert(scoreData) {
|
||||
const {
|
||||
studentId, courseId, teacherId,
|
||||
usual_score, midterm_score, final_score, score,
|
||||
gradePoint, gradeLevel, remark
|
||||
} = scoreData;
|
||||
|
||||
const existing = await this.findByStudentAndCourse(studentId, courseId);
|
||||
|
||||
// 处理参数:如果是 undefined 或空字符串,则设为 null
|
||||
const sanitize = (val) => (val === undefined || val === '' || val === null) ? null : val;
|
||||
|
||||
const params = [
|
||||
sanitize(usual_score),
|
||||
sanitize(midterm_score),
|
||||
sanitize(final_score),
|
||||
sanitize(score),
|
||||
sanitize(gradePoint),
|
||||
sanitize(gradeLevel),
|
||||
sanitize(remark)
|
||||
];
|
||||
|
||||
if (existing) {
|
||||
const sql = `UPDATE grades SET usual_score=?, midterm_score=?, final_score=?, total_score=?, grade_point=?, grade_level=?, remark=? WHERE id=?`;
|
||||
await db.query(sql, [...params, existing.id]);
|
||||
return existing.id;
|
||||
} else {
|
||||
const sql = `INSERT INTO grades (student_id, course_id, teacher_id, usual_score, midterm_score, final_score, total_score, grade_point, grade_level, created_at, remark) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now', 'localtime'), ?)`;
|
||||
const insertParams = [
|
||||
studentId, courseId, teacherId,
|
||||
...params
|
||||
];
|
||||
const result = await db.query(sql, insertParams);
|
||||
return result.insertId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Score;
|
||||
@@ -7,12 +7,33 @@ class Student {
|
||||
}
|
||||
|
||||
static async create(studentData) {
|
||||
const { id, name, className } = studentData;
|
||||
const { id, name, class: className, major, grade, contact_info } = studentData;
|
||||
await db.query(
|
||||
'INSERT INTO students (id, name, class) VALUES (?, ?, ?)',
|
||||
[id, name, className]
|
||||
'INSERT INTO students (id, name, class, major, grade, contact_info) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[id, name, className, major, grade, contact_info]
|
||||
);
|
||||
}
|
||||
|
||||
static async update(id, data) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
if (data.name) { fields.push('name = ?'); values.push(data.name); }
|
||||
if (data.class) { fields.push('class = ?'); values.push(data.class); }
|
||||
if (data.major !== undefined) { fields.push('major = ?'); values.push(data.major); }
|
||||
if (data.grade !== undefined) { fields.push('grade = ?'); values.push(data.grade); }
|
||||
if (data.contact_info !== undefined) { fields.push('contact_info = ?'); values.push(data.contact_info); }
|
||||
|
||||
if (fields.length === 0) return true;
|
||||
|
||||
values.push(id);
|
||||
const sql = `UPDATE students SET ${fields.join(', ')} WHERE id = ?`;
|
||||
await db.query(sql, values);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async delete(id) {
|
||||
await db.query('DELETE FROM students WHERE id = ?', [id]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Student;
|
||||
module.exports = Student;
|
||||
|
||||
32
backend/models/SystemSetting.js
Normal file
32
backend/models/SystemSetting.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const db = require('../config/database');
|
||||
|
||||
class SystemSetting {
|
||||
static async get(key) {
|
||||
const rows = await db.query('SELECT value FROM system_settings WHERE key = ?', [key]);
|
||||
return rows.length > 0 ? rows[0].value : null;
|
||||
}
|
||||
|
||||
static async getAll() {
|
||||
const rows = await db.query('SELECT key, value FROM system_settings');
|
||||
const settings = {};
|
||||
rows.forEach(row => {
|
||||
settings[row.key] = row.value;
|
||||
});
|
||||
return settings;
|
||||
}
|
||||
|
||||
static async set(key, value) {
|
||||
return await db.query(
|
||||
'INSERT INTO system_settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value',
|
||||
[key, value]
|
||||
);
|
||||
}
|
||||
|
||||
static async setMany(settings) {
|
||||
for (const [key, value] of Object.entries(settings)) {
|
||||
await this.set(key, String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SystemSetting;
|
||||
38
backend/models/Teacher.js
Normal file
38
backend/models/Teacher.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const db = require('../config/database');
|
||||
|
||||
class Teacher {
|
||||
static async findById(id) {
|
||||
const teachers = await db.query('SELECT * FROM teachers WHERE id = ?', [id]);
|
||||
return teachers[0];
|
||||
}
|
||||
|
||||
static async create(teacherData) {
|
||||
const { id, name, department, title, contact_info } = teacherData;
|
||||
await db.query(
|
||||
'INSERT INTO teachers (id, name, department, title, contact_info) VALUES (?, ?, ?, ?, ?)',
|
||||
[id, name, department, title, contact_info]
|
||||
);
|
||||
}
|
||||
|
||||
static async update(id, data) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
if (data.name) { fields.push('name = ?'); values.push(data.name); }
|
||||
if (data.department) { fields.push('department = ?'); values.push(data.department); }
|
||||
if (data.title !== undefined) { fields.push('title = ?'); values.push(data.title); }
|
||||
if (data.contact_info !== undefined) { fields.push('contact_info = ?'); values.push(data.contact_info); }
|
||||
|
||||
if (fields.length === 0) return true;
|
||||
|
||||
values.push(id);
|
||||
const sql = `UPDATE teachers SET ${fields.join(', ')} WHERE id = ?`;
|
||||
await db.query(sql, values);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async delete(id) {
|
||||
await db.query('DELETE FROM teachers WHERE id = ?', [id]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Teacher;
|
||||
@@ -35,6 +35,27 @@ class User {
|
||||
await db.query('UPDATE users SET password = ? WHERE id = ?', [hashedPassword, id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async updateProfile(id, updateData) {
|
||||
const fields = [];
|
||||
const params = [];
|
||||
|
||||
if (updateData.name) {
|
||||
fields.push('name = ?');
|
||||
params.push(updateData.name);
|
||||
}
|
||||
if (updateData.class !== undefined) {
|
||||
fields.push('class = ?');
|
||||
params.push(updateData.class);
|
||||
}
|
||||
|
||||
if (fields.length === 0) return false;
|
||||
|
||||
params.push(id);
|
||||
const sql = `UPDATE users SET ${fields.join(', ')} WHERE id = ?`;
|
||||
await db.query(sql, params);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = User;
|
||||
Reference in New Issue
Block a user