|
|
// 导入学生名单(从Excel)
|
|
|
app.post('/import-students', upload.single('file'), async (req, res) => {
|
|
|
try {
|
|
|
const file = req.file;
|
|
|
const workbook = xlsx.readFile(file.path);
|
|
|
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
|
const students = xlsx.utils.sheet_to_json(sheet); // 解析Excel数据
|
|
|
|
|
|
// 批量插入数据库
|
|
|
for (const student of students) {
|
|
|
await db.execute(
|
|
|
'INSERT INTO students (student_id, name, major) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE name=?, major=?',
|
|
|
[student.学号, student.姓名, student.专业, student.姓名, student.专业]
|
|
|
);
|
|
|
}
|
|
|
res.json({ success: true, message: '导入成功' });
|
|
|
} catch (err) {
|
|
|
res.status(500).json({ success: false, error: err.message });
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 随机点名(根据积分调整概率:积分越高,概率越低)
|
|
|
app.get('/random-call', async (req, res) => {
|
|
|
try {
|
|
|
// 查询所有学生的积分和学号
|
|
|
const [students] = await db.execute('SELECT student_id, name, score FROM students');
|
|
|
|
|
|
// 计算权重(积分倒数,避免0积分导致权重无穷大)
|
|
|
const totalWeight = students.reduce((sum, s) => sum + (1 / (s.score + 1)), 0);
|
|
|
let random = Math.random() * totalWeight;
|
|
|
let selected;
|
|
|
|
|
|
// 根据权重随机选择学生
|
|
|
for (const s of students) {
|
|
|
const weight = 1 / (s.score + 1);
|
|
|
if (random <= weight) {
|
|
|
selected = s;
|
|
|
break;
|
|
|
}
|
|
|
random -= weight;
|
|
|
}
|
|
|
|
|
|
// 记录点名信息并更新随机点名次数
|
|
|
await db.execute(
|
|
|
'INSERT INTO attendance (student_id, mode) VALUES (?, ?)',
|
|
|
[selected.student_id, 'random']
|
|
|
);
|
|
|
await db.execute(
|
|
|
'UPDATE students SET random_count = random_count + 1 WHERE student_id = ?',
|
|
|
[selected.student_id]
|
|
|
);
|
|
|
|
|
|
res.json({ success: true, student: selected });
|
|
|
} catch (err) {
|
|
|
res.status(500).json({ success: false, error: err.message });
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 更新学生积分(例如:回答问题后)
|
|
|
app.post('/update-score', async (req, res) => {
|
|
|
const { student_id, answer_score } = req.body;
|
|
|
try {
|
|
|
// 先获取当前积分
|
|
|
const [rows] = await db.execute('SELECT score FROM students WHERE student_id = ?', [student_id]);
|
|
|
const currentScore = rows[0].score;
|
|
|
|
|
|
// 更新积分(出勤+1分已在点名时处理,此处仅处理回答问题得分)
|
|
|
const newScore = currentScore + answer_score;
|
|
|
await db.execute(
|
|
|
'UPDATE students SET score = ? WHERE student_id = ?',
|
|
|
[newScore, student_id]
|
|
|
);
|
|
|
// 同步更新点名记录的回答得分
|
|
|
await db.execute(
|
|
|
'UPDATE attendance SET answer_score = ? WHERE student_id = ? ORDER BY attendance_time DESC LIMIT 1',
|
|
|
[answer_score, student_id]
|
|
|
);
|
|
|
res.json({ success: true, newScore });
|
|
|
} catch (err) {
|
|
|
res.status(500).json({ success: false, error: err.message });
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 导出积分详单(生成Excel)
|
|
|
app.get('/export-scores', async (req, res) => {
|
|
|
try {
|
|
|
const [students] = await db.execute(
|
|
|
'SELECT student_id, name, major, random_count, score FROM students'
|
|
|
);
|
|
|
const worksheet = xlsx.utils.json_to_sheet(students);
|
|
|
const workbook = xlsx.utils.book_new();
|
|
|
xlsx.utils.book_append_sheet(workbook, worksheet, '积分详单');
|
|
|
const buffer = xlsx.write(workbook, { type: 'buffer', bookType: 'xlsx' });
|
|
|
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
|
res.setHeader('Content-Disposition', 'attachment; filename="scores.xlsx"');
|
|
|
res.send(buffer);
|
|
|
} catch (err) {
|
|
|
res.status(500).json({ success: false, error: err.message });
|
|
|
}
|
|
|
}); |