Files
WebWork/backend/init_db.js
祀梦 b1da021185 feat: 实现教师资料更新、操作日志和系统设置功能
新增教师资料更新功能,包括个人信息修改和密码更新
添加操作日志记录系统,记录用户关键操作
实现系统设置模块,支持动态配置系统参数
重构数据库模型,新增教师表和系统设置表
优化成绩录入逻辑,支持平时分、期中和期末成绩计算
添加数据导出功能,支持学生、教师和成绩数据导出
完善管理员后台,增加统计图表和操作日志查看
2025-12-22 23:30:01 +08:00

344 lines
12 KiB
JavaScript

const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const bcrypt = require('bcryptjs');
const dbPath = path.resolve(__dirname, 'database.sqlite');
const db = new sqlite3.Database(dbPath);
const run = (sql, params = []) => {
return new Promise((resolve, reject) => {
db.run(sql, params, function(err) {
if (err) reject(err);
else resolve(this);
});
});
};
const insertUser = async (user) => {
await run(
'INSERT INTO users (id, name, password, role, class) VALUES (?, ?, ?, ?, ?)',
[user.id, user.name, user.password, user.role, user.class]
);
};
const insertStudent = async (student) => {
await run(
'INSERT INTO students (id, name, class, major, grade, contact_info) VALUES (?, ?, ?, ?, ?, ?)',
[student.id, student.name, student.class, student.major, student.grade, student.contact_info]
);
};
const insertClass = async (cls) => {
return await run(
'INSERT INTO classes (class_name, grade, major, teacher_id) VALUES (?, ?, ?, ?)',
[cls.class_name, cls.grade, cls.major, cls.teacher_id]
);
};
const insertCourse = async (course) => {
return await run(
'INSERT INTO courses (course_code, course_name, credit, teacher_id, class_id, semester, academic_year, category) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
[course.course_code, course.course_name, course.credit, course.teacher_id, course.class_id, course.semester, course.academic_year, course.category]
);
};
const insertGrade = async (grade) => {
await run(
`INSERT INTO grades (
student_id, course_id, teacher_id,
usual_score, midterm_score, final_score, total_score,
grade_point, grade_level, remark
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
grade.student_id, grade.course_id, grade.teacher_id,
grade.usual_score, grade.midterm_score, grade.final_score, grade.total_score,
grade.grade_point, grade.grade_level, grade.remark
]
);
};
// Helper to calculate grade point
const calculateGradePoint = (score) => {
if (score >= 90) return 4.0;
if (score >= 85) return 3.7;
if (score >= 82) return 3.3;
if (score >= 78) return 3.0;
if (score >= 75) return 2.7;
if (score >= 72) return 2.3;
if (score >= 68) return 2.0;
if (score >= 64) return 1.5;
if (score >= 60) return 1.0;
return 0.0;
};
const calculateGradeLevel = (score) => {
if (score >= 90) return 'A';
if (score >= 80) return 'B';
if (score >= 70) return 'C';
if (score >= 60) return 'D';
return 'F';
};
const init = async () => {
console.log('开始初始化 SQLite 数据库...');
const hashedPassword = await bcrypt.hash('123456', 10);
try {
// Drop tables
await run('DROP TABLE IF EXISTS grades');
await run('DROP TABLE IF EXISTS courses');
await run('DROP TABLE IF EXISTS classes');
await run('DROP TABLE IF EXISTS students');
await run('DROP TABLE IF EXISTS users');
await run('DROP TABLE IF EXISTS operation_logs');
// Create tables
console.log('创建表结构...');
await run(`
CREATE TABLE users (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
password TEXT NOT NULL,
role TEXT NOT NULL,
class TEXT,
created_at TEXT DEFAULT (datetime('now', 'localtime'))
)
`);
await run(`
CREATE TABLE students (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
class TEXT,
major TEXT,
grade TEXT,
contact_info TEXT,
FOREIGN KEY (id) REFERENCES users(id) ON DELETE CASCADE
)
`);
await run(`
CREATE TABLE classes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
class_name TEXT NOT NULL,
grade TEXT,
major TEXT,
teacher_id TEXT,
created_at TEXT DEFAULT (datetime('now', 'localtime'))
)
`);
await run(`
CREATE TABLE courses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_code TEXT UNIQUE NOT NULL,
course_name TEXT NOT NULL,
credit REAL DEFAULT 2.0,
teacher_id TEXT NOT NULL,
class_id INTEGER NOT NULL,
semester TEXT,
academic_year TEXT,
category TEXT,
created_at TEXT DEFAULT (datetime('now', 'localtime'))
)
`);
await run(`
CREATE TABLE grades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id TEXT NOT NULL,
course_id INTEGER NOT NULL,
teacher_id TEXT NOT NULL,
usual_score REAL,
midterm_score REAL,
final_score REAL,
total_score REAL,
grade_point REAL,
grade_level TEXT,
remark TEXT,
created_at TEXT DEFAULT (datetime('now', 'localtime')),
UNIQUE(student_id, course_id)
)
`);
await run(`
CREATE TABLE operation_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT,
operation_type TEXT,
operation_target TEXT,
description TEXT,
ip_address TEXT,
created_at TEXT DEFAULT (datetime('now', 'localtime'))
)
`);
console.log('生成基础数据...');
// 1. Admin
await insertUser({
id: 'admin',
name: '系统管理员',
password: hashedPassword,
role: 'admin',
class: null
});
// 2. Teachers (20 teachers)
const teachers = [];
for (let i = 1; i <= 20; i++) {
const id = `T${1000 + i}`;
const name = `教师${String.fromCharCode(65 + (i % 26))}${i}`;
await insertUser({
id,
name,
password: hashedPassword,
role: 'teacher',
class: null
});
teachers.push(id);
}
// 3. Classes (10 classes)
const majors = ['软件工程', '计算机科学', '信息管理'];
const classIds = [];
const classes = [];
for (let i = 1; i <= 10; i++) {
const major = majors[i % 3];
const gradeYear = 2021 + Math.floor((i-1)/5); // 2021, 2022
const className = `${major.substr(0, 2)}${gradeYear}${String(i).padStart(2, '0')}`;
const teacherId = teachers[i % teachers.length];
const result = await insertClass({
class_name: className,
grade: String(gradeYear),
major: major,
teacher_id: teacherId
});
classIds.push(result.lastID);
classes.push({ id: result.lastID, name: className, year: gradeYear, major });
}
// 4. Students (50 per class -> 500 students)
console.log('生成学生数据...');
const students = [];
for (let clsIdx = 0; clsIdx < classes.length; clsIdx++) {
const cls = classes[clsIdx];
for (let i = 1; i <= 50; i++) {
const id = `${cls.year}${String(clsIdx + 1).padStart(2, '0')}${String(i).padStart(3, '0')}`;
const name = `学生${cls.name.substr(0,1)}${i}`;
await insertUser({
id,
name,
password: hashedPassword,
role: 'student',
class: cls.name
});
await insertStudent({
id,
name,
class: cls.name,
major: cls.major,
grade: String(cls.year),
contact_info: `13800${id.substr(0, 6)}`
});
students.push({ id, classId: cls.id });
}
}
// 5. Courses and Grades
console.log('生成课程和成绩数据...');
const courseNames = [
{ name: '高等数学', credit: 4, category: '必修' },
{ name: '大学英语', credit: 3, category: '必修' },
{ name: '程序设计基础', credit: 4, category: '必修' },
{ name: '数据结构', credit: 4, category: '必修' },
{ name: '操作系统', credit: 3, category: '必修' },
{ name: '计算机网络', credit: 3, category: '必修' },
{ name: '数据库原理', credit: 3, category: '必修' },
{ name: '软件工程导论', credit: 2, category: '必修' },
{ name: 'Web开发技术', credit: 3, category: '选修' },
{ name: '人工智能基础', credit: 2, category: '选修' },
{ name: '大数据分析', credit: 2, category: '选修' },
{ name: '音乐鉴赏', credit: 1, category: '通识' },
{ name: '心理健康', credit: 1, category: '通识' },
{ name: '职业规划', credit: 1, category: '通识' }
];
const semesters = ['2021-2022-1', '2021-2022-2', '2022-2023-1', '2022-2023-2', '2023-2024-1'];
for (const cls of classes) {
// For each class, assign some courses
for (let semIdx = 0; semIdx < semesters.length; semIdx++) {
const semester = semesters[semIdx];
// Select random 5-8 courses for this semester
const semCourses = courseNames.sort(() => 0.5 - Math.random()).slice(0, 6);
for (const cTemplate of semCourses) {
const teacherId = teachers[Math.floor(Math.random() * teachers.length)];
const courseCode = `C${cls.id}${semIdx}${Math.floor(Math.random() * 1000)}`;
const result = await insertCourse({
course_code: courseCode,
course_name: cTemplate.name,
credit: cTemplate.credit,
teacher_id: teacherId,
class_id: cls.id,
semester: semester,
academic_year: semester.substring(0, 9),
category: cTemplate.category
});
const courseId = result.lastID;
// Generate grades for students in this class
const classStudents = students.filter(s => s.classId === cls.id);
// Batch insert could be faster, but let's keep it simple for now
const stmt = db.prepare(`INSERT INTO grades (
student_id, course_id, teacher_id,
usual_score, midterm_score, final_score, total_score,
grade_point, grade_level, remark
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
for (const stu of classStudents) {
// 90% chance to have a grade
if (Math.random() > 0.1) {
const totalScore = Math.floor(Math.random() * 40) + 60; // 60-100 mostly
// 10% chance to fail
const finalTotal = Math.random() > 0.1 ? totalScore : Math.floor(Math.random() * 59);
stmt.run([
stu.id,
courseId,
teacherId,
finalTotal, // usual
finalTotal, // midterm
finalTotal, // final
finalTotal, // total
calculateGradePoint(finalTotal),
calculateGradeLevel(finalTotal),
''
]);
}
}
stmt.finalize();
}
}
}
console.log('数据库初始化完成!');
db.close();
} catch (err) {
console.error('Initialization failed:', err);
process.exit(1);
}
};
init();