core v1
This commit is contained in:
212
server/internal/handlers/handlers_student.go
Normal file
212
server/internal/handlers/handlers_student.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
internalDb "server/internal/db"
|
||||
"server/internal/models"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type studentShiftItem struct {
|
||||
Period int `json:"period"`
|
||||
CourseName string `json:"courseName"`
|
||||
StartTime string `json:"startTime"`
|
||||
EndTime string `json:"endTime"`
|
||||
IsActiveNow bool `json:"isActiveNow"`
|
||||
OnlineSeconds int `json:"onlineSeconds"`
|
||||
OfflineSeconds int `json:"offlineSeconds"`
|
||||
AttendanceStatus int `json:"attendanceStatus"`
|
||||
AttendanceLabel string `json:"attendanceLabel"`
|
||||
}
|
||||
|
||||
// GET /api/student/status — trạng thái giám sát, lớp/ca hiện tại, tích lũy & điểm danh hôm nay
|
||||
func GetStudentStatusHandler(db *gorm.DB) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
studentID, err := strconv.ParseInt(c.Query("studentRkId", "0"), 10, 64)
|
||||
if err != nil || studentID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "studentRkId is required"})
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
today := now.Format("2006-01-02")
|
||||
dayIdx := weekdayIndex(now)
|
||||
currMin := now.Hour()*60 + now.Minute()
|
||||
|
||||
classID, activePeriod := internalDb.FindActiveClassAndPeriodForStudent(db, studentID)
|
||||
if classID <= 0 {
|
||||
var link models.ClassStudent
|
||||
if err := db.Where("student_rk_id = ?", studentID).First(&link).Error; err == nil {
|
||||
classID = link.ClassRkID
|
||||
}
|
||||
}
|
||||
|
||||
className, classCode := "", ""
|
||||
if classID > 0 {
|
||||
var cl models.Class
|
||||
if err := db.Where("rk_id = ?", classID).First(&cl).Error; err == nil {
|
||||
className = cl.Name
|
||||
classCode = cl.ClassCode
|
||||
}
|
||||
}
|
||||
|
||||
var todaySchedules []models.ClassSchedule
|
||||
if classID > 0 {
|
||||
_ = db.Where("class_rk_id = ? AND day_of_week = ? AND is_active = ?", classID, dayIdx, true).
|
||||
Order("period asc, start_time asc").Find(&todaySchedules).Error
|
||||
}
|
||||
|
||||
inScheduleNow := false
|
||||
currentPeriod := 0
|
||||
currentCourse, currentStart, currentEnd := "", "", ""
|
||||
for _, s := range todaySchedules {
|
||||
startMin := parseTimeMinutes(s.StartTime)
|
||||
endMin := parseTimeMinutes(s.EndTime)
|
||||
if currMin >= startMin && currMin <= endMin {
|
||||
inScheduleNow = true
|
||||
currentPeriod = s.Period
|
||||
if currentPeriod < 1 {
|
||||
currentPeriod = 1
|
||||
}
|
||||
currentCourse = s.CourseName
|
||||
currentStart = s.StartTime
|
||||
currentEnd = s.EndTime
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inScheduleNow && activePeriod > 0 {
|
||||
currentPeriod = activePeriod
|
||||
}
|
||||
|
||||
hasApps := false
|
||||
keywords := ""
|
||||
if classID > 0 {
|
||||
var appConfig models.ClassAllowedApp
|
||||
if err := db.Where("class_rk_id = ?", classID).First(&appConfig).Error; err == nil {
|
||||
keywords = strings.TrimSpace(appConfig.Keywords)
|
||||
hasApps = keywords != ""
|
||||
}
|
||||
}
|
||||
|
||||
monitorMode := "outside_schedule"
|
||||
monitorLabel := "Ngoài giờ học"
|
||||
if classID <= 0 {
|
||||
monitorMode = "not_configured"
|
||||
monitorLabel = "Chưa xác định được lớp học"
|
||||
} else if !hasApps {
|
||||
monitorMode = "not_configured"
|
||||
monitorLabel = "Lớp chưa cấu hình ứng dụng được phép"
|
||||
} else if inScheduleNow {
|
||||
monitorMode = "learning"
|
||||
if currentCourse != "" {
|
||||
monitorLabel = fmt.Sprintf("Ca %d — %s (%s–%s)", currentPeriod, currentCourse, currentStart, currentEnd)
|
||||
} else {
|
||||
monitorLabel = fmt.Sprintf("Đang giám sát — Ca %d", currentPeriod)
|
||||
}
|
||||
}
|
||||
// monitorMode = "exam" — dành cho phòng thi (sẽ bổ sung sau)
|
||||
|
||||
sessionMap := map[int]models.StudentSession{}
|
||||
attMap := map[int]models.AttendanceResult{}
|
||||
if classID > 0 {
|
||||
var sessions []models.StudentSession
|
||||
_ = db.Where("student_rk_id = ? AND class_rk_id = ? AND session_date = ?", studentID, classID, today).Find(&sessions).Error
|
||||
for _, s := range sessions {
|
||||
p := s.Period
|
||||
if p < 1 {
|
||||
p = 1
|
||||
}
|
||||
sessionMap[p] = s
|
||||
}
|
||||
var attendances []models.AttendanceResult
|
||||
_ = db.Where("student_rk_id = ? AND class_rk_id = ? AND session_date = ?", studentID, classID, today).Find(&attendances).Error
|
||||
for _, a := range attendances {
|
||||
p := a.Period
|
||||
if p < 1 {
|
||||
p = 1
|
||||
}
|
||||
attMap[p] = a
|
||||
}
|
||||
}
|
||||
|
||||
shifts := make([]studentShiftItem, 0, len(todaySchedules))
|
||||
for _, sch := range todaySchedules {
|
||||
period := sch.Period
|
||||
if period < 1 {
|
||||
period = 1
|
||||
}
|
||||
sess := sessionMap[period]
|
||||
att := attMap[period]
|
||||
startMin := parseTimeMinutes(sch.StartTime)
|
||||
endMin := parseTimeMinutes(sch.EndTime)
|
||||
isActiveNow := currMin >= startMin && currMin <= endMin
|
||||
|
||||
attStatus := -1
|
||||
attLabel := "Chưa tính"
|
||||
if att.ID > 0 {
|
||||
attStatus = att.Status
|
||||
attLabel = att.StatusLabel
|
||||
if attLabel == "" {
|
||||
attLabel = attendanceLabelFallback(att.Status)
|
||||
}
|
||||
}
|
||||
|
||||
shifts = append(shifts, studentShiftItem{
|
||||
Period: period,
|
||||
CourseName: sch.CourseName,
|
||||
StartTime: sch.StartTime,
|
||||
EndTime: sch.EndTime,
|
||||
IsActiveNow: isActiveNow,
|
||||
OnlineSeconds: sess.OnlineSeconds,
|
||||
OfflineSeconds: sess.OfflineSeconds,
|
||||
AttendanceStatus: attStatus,
|
||||
AttendanceLabel: attLabel,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"sessionDate": today,
|
||||
"monitorMode": monitorMode,
|
||||
"monitorLabel": monitorLabel,
|
||||
"classRkId": classID,
|
||||
"className": className,
|
||||
"classCode": classCode,
|
||||
"currentPeriod": currentPeriod,
|
||||
"currentCourseName": currentCourse,
|
||||
"currentShiftStart": currentStart,
|
||||
"currentShiftEnd": currentEnd,
|
||||
"inScheduleNow": inScheduleNow,
|
||||
"blockerActive": hasApps && inScheduleNow,
|
||||
"allowedKeywords": keywords,
|
||||
"shifts": shifts,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func weekdayIndex(t time.Time) int {
|
||||
wd := t.Weekday()
|
||||
if wd == time.Sunday {
|
||||
return 6
|
||||
}
|
||||
return int(wd) - 1
|
||||
}
|
||||
|
||||
func attendanceLabelFallback(status int) string {
|
||||
switch status {
|
||||
case 1:
|
||||
return "Nghỉ có phép"
|
||||
case 2:
|
||||
return "Nghỉ nửa buổi"
|
||||
case 3:
|
||||
return "Đi học muộn"
|
||||
case 4:
|
||||
return "Đi học đầy đủ"
|
||||
default:
|
||||
return "Nghỉ không phép"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user