You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
6.0 KiB
168 lines
6.0 KiB
import Attendance from '../models/attendanceModel.js';
|
|
import Student from '../models/studentModel.js';
|
|
import axios from 'axios';
|
|
|
|
// 教师发布考勤
|
|
export const createAttendance = async (req, res) => {
|
|
const { username, studentIds, duration, isRandom } = req.body;
|
|
|
|
try {
|
|
const attendance = new Attendance({
|
|
username,
|
|
studentIds,
|
|
duration,
|
|
rollcallTime: new Date(),
|
|
isRandom // 新增字段,表示是否为抽点
|
|
});
|
|
|
|
await attendance.save();
|
|
|
|
// 发送通知给学生
|
|
if (isRandom) {
|
|
// 抽点逻辑
|
|
const selectedStudent = await randomCall(studentIds);
|
|
if (selectedStudent && selectedStudent.openId) {
|
|
await sendTemplateMessage(selectedStudent.openId, attendance.rollcallTime);
|
|
}
|
|
} else {
|
|
// 全点逻辑,发送通知给所有学生
|
|
for (const studentId of studentIds) {
|
|
const student = await Student.findById(studentId);
|
|
if (student && student.openId) {
|
|
await sendTemplateMessage(student.openId, attendance.rollcallTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 设置超时处理
|
|
setTimeout(async () => {
|
|
attendance.status = 'completed';
|
|
await attendance.save();
|
|
|
|
// 更新未签到学生的考勤记录
|
|
for (const studentId of studentIds) {
|
|
if (!attendance.results.some(result => result.studentId.equals(studentId))) {
|
|
attendance.results.push({ studentId, status: 'absent' });
|
|
await Student.findByIdAndUpdate(studentId, { $inc: { points: -1 } });
|
|
}
|
|
}
|
|
await attendance.save();
|
|
}, duration * 60 * 1000); // duration 转换为毫秒
|
|
|
|
res.status(201).json({ message: '考勤发布成功', attendance });
|
|
} catch (error) {
|
|
res.status(500).json({ message: '发布考勤失败', error: error.message });
|
|
}
|
|
};
|
|
|
|
// 随机点名逻辑
|
|
async function randomCall(studentIds) {
|
|
const students = await Student.find({ String: { $in: studentIds } });
|
|
|
|
// 计算总积分的概率
|
|
const totalPoints = students.reduce((acc, student) => acc + Math.max(0, 100 - student.points), 0);
|
|
const randomNum = Math.random() * totalPoints;
|
|
let cumulativePoints = 0;
|
|
let selectedStudent = null;
|
|
|
|
for (const student of students) {
|
|
cumulativePoints += Math.max(0, 100 - student.points);
|
|
if (randomNum <= cumulativePoints) {
|
|
selectedStudent = student;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return selectedStudent; // 返回被抽中的学生
|
|
}
|
|
|
|
// 发送模板消息的函数
|
|
async function sendTemplateMessage(openId, rollcallTime) {
|
|
const accessToken = await getAccessToken(); // 获取 access_token
|
|
const templateMessage = {
|
|
touser: openId,
|
|
template_id: 'ca8117c1133660af421ad67eab9054e7', // 替换为您的模板 ID
|
|
data: {
|
|
keyword1: { value: '您有一条签到' },
|
|
keyword2: { value: rollcallTime.toISOString() }, // 或者格式化成需要的日期格式
|
|
}
|
|
};
|
|
|
|
try {
|
|
await axios.post(`https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${accessToken}`, templateMessage);
|
|
} catch (error) {
|
|
console.error('发送模板消息失败:', error);
|
|
}
|
|
}
|
|
|
|
// 获取 access_token 的函数
|
|
async function getAccessToken() {
|
|
const appId = 'wx0874fe247e4282a3'; // 替换为您的微信小程序 appId
|
|
const appSecret = 'ca8117c1133660af421ad67eab9054e7'; // 替换为您的微信小程序 appSecret
|
|
|
|
try {
|
|
const response = await axios.get(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`);
|
|
return response.data.access_token; // 返回获取到的 access_token
|
|
} catch (error) {
|
|
console.error('获取 access_token 失败:', error);
|
|
throw new Error('获取 access_token 失败');
|
|
}
|
|
}
|
|
|
|
// 学生签到
|
|
export const studentCheckIn = async (req, res) => {
|
|
const { studentId } = req.body; // 从请求体中获取 studentId
|
|
const rollcallTime = new Date().toISOString(); // 自动获取当前时间
|
|
console.log('签到请求:', { studentId, rollcallTime });
|
|
try {
|
|
// 找到当天的考勤记录
|
|
const attendance = await Attendance.findOne({ rollcallTime });
|
|
if (!attendance) {
|
|
return res.status(404).json({ message: '考勤记录未找到' });
|
|
}
|
|
|
|
// 检查学生是否在考勤名单中
|
|
if (!attendance.studentIds.includes(studentId)) {
|
|
return res.status(403).json({ message: '您不在考勤名单中' });
|
|
}
|
|
|
|
// 检查学生是否已经签到
|
|
const existingResult = attendance.results.find(result => result.studentId.equals(studentId));
|
|
if (existingResult) {
|
|
return res.status(400).json({ message: '您已签到' });
|
|
}
|
|
|
|
// 签到成功
|
|
attendance.results.push({ studentId, status: 'present' });
|
|
await Student.findByIdAndUpdate(studentId, { $inc: { points: 1 } }); // 积分加1
|
|
await attendance.save();
|
|
res.json({ message: '签到成功' });
|
|
} catch (error) {
|
|
res.status(500).json({ message: '签到失败', error: error.message });
|
|
}
|
|
}
|
|
|
|
// 获取教师的考勤记录
|
|
export const getAttendanceRecords = async (req, res) => {
|
|
const { username } = req.params;
|
|
|
|
try {
|
|
const records = await Attendance.find({ username }).populate('studentIds').populate('results.studentId');
|
|
res.json(records);
|
|
} catch (error) {
|
|
res.status(500).json({ message: '获取考勤记录失败', error: error.message || error });
|
|
}
|
|
};
|
|
|
|
// 获取学生的考勤记录
|
|
export const getStudentAttendance = async (req, res) => {
|
|
const { studentId } = req.params;
|
|
|
|
try {
|
|
const records = await Attendance.find({ 'results.studentId': studentId }).populate('results.studentId');
|
|
res.json(records);
|
|
} catch (error) {
|
|
res.status(500).json({ message: '获取学生考勤记录失败', error: error.message || error });
|
|
}
|
|
};
|