基于Go的学生考勤Web应用后端逻辑实现咨询
学生考勤按钮后端逻辑实现方案
1. 新增出勤记录结构体与数据库表
首先需要定义存储每日考勤状态的结构体,同时在数据库中创建对应表,确保每个学生每天只有一条考勤记录:
// 以Go语言为例,可根据自身技术栈调整 type AttendanceRecord struct { ID uint `gorm:"primaryKey"` StudentID uint `gorm:"index"` // 关联学生表ID AttendDate time.Time `gorm:"index"` // 考勤日期 IsPresent bool // true=出勤,false=缺勤 }
对应的MySQL表结构:
CREATE TABLE attendance_records ( id INT AUTO_INCREMENT PRIMARY KEY, student_id INT NOT NULL, attend_date DATE NOT NULL, is_present BOOLEAN NOT NULL, FOREIGN KEY (student_id) REFERENCES students(id), UNIQUE KEY unique_student_date (student_id, attend_date) -- 防止重复提交同一日期考勤 );
2. 实现考勤提交接口
后端新增MarkAttendance接口,处理前端按钮的提交请求,逻辑为:校验参数→查询当日是否已有记录→更新或插入记录:
func MarkAttendance(c *gin.Context) { studentID, _ := strconv.Atoi(c.PostForm("student_id")) attendDate, _ := time.Parse("2006-01-02", c.PostForm("date")) isPresent := c.PostForm("is_present") == "true" // 校验学生是否存在 var student Student if err := db.First(&student, studentID).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "学生不存在"}) return } // 处理考勤记录 var record AttendanceRecord if err := db.Where("student_id = ? AND attend_date = ?", studentID, attendDate).First(&record).Error; err != nil { // 无记录则创建 record = AttendanceRecord{ StudentID: uint(studentID), AttendDate: attendDate, IsPresent: isPresent, } db.Create(&record) } else { // 有记录则更新状态 db.Model(&record).Update("is_present", isPresent) } c.JSON(http.StatusOK, gin.H{"message": "考勤记录已更新"}) }
3. 前端按钮请求绑定
在list.html中给Yes/No按钮绑定点击事件,发送POST请求到后端接口:
{{range .students}} <div class="student-item"> <span>{{.Name}}</span> <button onclick="markAttendance({{.ID}}, '{{.Today}}', true)">Yes</button> <button onclick="markAttendance({{.ID}}, '{{.Today}}', false)">No</button> </div> {{end}} <script> function markAttendance(studentId, date, isPresent) { fetch('/api/mark-attendance', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `student_id=${studentId}&date=${date}&is_present=${isPresent}` }) .then(response => response.json()) .then(data => { alert(data.message); // 可添加按钮状态更新逻辑,比如高亮已选状态 }) .catch(error => console.error('提交失败:', error)); } </script>
注:.Today是后端传递给前端的当日日期,格式为YYYY-MM-DD。
4. 月度考勤表查询逻辑
要实现学生为行、日期为列的考勤表,需按月份查询并整理数据:
func GetMonthlyAttendance(c *gin.Context) { year, _ := strconv.Atoi(c.Query("year")) month, _ := strconv.Atoi(c.Query("month")) // 获取当月首尾日期 firstDay := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC) lastDay := firstDay.AddDate(0, 1, -1) // 查询所有学生 var students []Student db.Find(&students) // 查询当月所有考勤记录 var records []AttendanceRecord db.Where("attend_date BETWEEN ? AND ?", firstDay, lastDay).Find(&records) // 构建学生-日期-状态的映射 attendanceMap := make(map[uint]map[string]bool) for _, record := range records { if _, ok := attendanceMap[record.StudentID]; !ok { attendanceMap[record.StudentID] = make(map[string]bool) } dateStr := record.AttendDate.Format("2006-01-02") attendanceMap[record.StudentID][dateStr] = record.IsPresent } // 整理为前端可用结构 type StudentAttendance struct { Student Student DailyStatus map[string]bool } var result []StudentAttendance for _, student := range students { status := attendanceMap[student.ID] if status == nil { status = make(map[string]bool) } result = append(result, StudentAttendance{Student: student, DailyStatus: status}) } c.JSON(http.StatusOK, result) }
前端拿到数据后,可循环生成表格:行对应学生,列对应当月日期,根据DailyStatus的值渲染出勤(如绿色√)或缺勤(如红色×)标记。
内容的提问来源于stack exchange,提问作者Awesome Lerman
相关产品推荐
相关产品推荐

