package handlers import ( "crypto/rand" "encoding/hex" "fmt" "net/http" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // DetectionService 检测服务 type DetectionService struct { DB *gorm.DB } // StartDetectionRequest 发起检测请求 type StartDetectionRequest struct { ClassID uint `json:"class_id" binding:"required"` TeacherID uint `json:"teacher_id" binding:"required"` StudentCount int `json:"student_count" binding:"required"` DetectionType string `json:"detection_type" binding:"required,oneof=vision fatigue training"` // vision, fatigue, training StartTime *time.Time `json:"start_time"` } // StartDetectionResponse 发起检测响应 type StartDetectionResponse struct { Code int `json:"code"` Message string `json:"message"` Data struct { TaskID string `json:"task_id"` TaskNo string `json:"task_no"` StartTime time.Time `json:"start_time"` } `json:"data"` } // SubmitDetectionRequest 提交检测结果请求 type SubmitDetectionRequest struct { StudentID uint `json:"student_id" binding:"required"` DetectionID string `json:"detection_id" binding:"required"` Vision VisionData `json:"vision"` EyeMovement EyeMovementData `json:"eye_movement"` Response ResponseData `json:"response"` Timestamp int64 `json:"timestamp"` DeviceID *uint `json:"device_id"` } // SubmitDetectionResponse 提交检测结果响应 type SubmitDetectionResponse struct { Code int `json:"code"` Message string `json:"message"` Data struct { ID string `json:"id"` } `json:"data"` } // GetDetectionReportRequest 获取检测报告请求 type GetDetectionReportRequest struct { DetectionID string `json:"detection_id" uri:"detection_id"` StudentID uint `json:"student_id" uri:"student_id"` } // GetDetectionReportResponse 获取检测报告响应 type GetDetectionReportResponse struct { Code int `json:"code"` Message string `json:"message"` Data DetectionReport `json:"data"` } // GetDetectionHistoryRequest 获取检测历史请求 type GetDetectionHistoryRequest struct { StudentID uint `form:"student_id"` ClassID uint `form:"class_id"` StartDate time.Time `form:"start_date"` EndDate time.Time `form:"end_date"` Page int `form:"page,default=1"` PageSize int `form:"page_size,default=20"` } // GetDetectionHistoryResponse 获取检测历史响应 type GetDetectionHistoryResponse struct { Code int `json:"code"` Message string `json:"message"` Data struct { Items []DetectionHistory `json:"items"` Total int `json:"total"` Page int `json:"page"` } `json:"data"` } // GetClassStatsRequest 获取班级统计请求 type GetClassStatsRequest struct { ClassID uint `form:"class_id" uri:"class_id" binding:"required"` StartDate time.Time `form:"start_date"` EndDate time.Time `form:"end_date"` } // GetClassStatsResponse 获取班级统计响应 type GetClassStatsResponse struct { Code int `json:"code"` Message string `json:"message"` Data ClassStats `json:"data"` } // ClassStats 班级统计数据 type ClassStats struct { ClassID uint `json:"class_id"` ClassName string `json:"class_name"` TotalStudents int `json:"total_students"` TestedStudents int `json:"tested_students"` AvgVisionLeft float64 `json:"avg_vision_left"` AvgVisionRight float64 `json:"avg_vision_right"` VisionDeclineCount int `json:"vision_decline_count"` AvgFatigueScore float64 `json:"avg_fatigue_score"` AlertCount int `json:"alert_count"` AlertDistribution map[string]int `json:"alert_distribution"` CreatedAt time.Time `json:"created_at"` } // VisionData 视力数据 type VisionData struct { VisionLeft float64 `json:"vision_left"` VisionRight float64 `json:"vision_right"` Confidence string `json:"confidence"` // high, medium, low } // EyeMovementData 眼动数据 type EyeMovementData struct { LeftEye PupilData `json:"left_eye"` RightEye PupilData `json:"right_eye"` GazePoint GazePoint `json:"gaze_point"` Timestamp int64 `json:"timestamp"` } // PupilData 瞳孔数据 type PupilData struct { X float64 `json:"x"` Y float64 `json:"y"` Radius float64 `json:"radius"` Confidence float64 `json:"confidence"` } // GazePoint 注视点 type GazePoint struct { X float64 `json:"x"` Y float64 `json:"y"` Confidence float64 `json:"confidence"` } // ResponseData 响应数据 type ResponseData struct { Accuracy float64 `json:"accuracy"` // 准确率 ResponseType float64 `json:"response_time"` // 响应时间 Errors int `json:"errors"` // 错误次数 } // DetectionReport 检测报告 type DetectionReport struct { ID uint `json:"id"` StudentID uint `json:"student_id"` Student interface{} `json:"student"` DetectionID uint `json:"detection_id"` Detection interface{} `json:"detection"` Vision VisionData `json:"vision"` EyeMovement EyeMovementData `json:"eye_movement"` Response ResponseData `json:"response"` FatigueScore float64 `json:"fatigue_score"` AlertLevel string `json:"alert_level"` // normal, warning, alert AIAnalysis interface{} `json:"ai_analysis"` // AI分析结果 CreatedAt time.Time `json:"created_at"` } // DetectionHistory 检测历史 type DetectionHistory struct { ID uint `json:"id"` StudentID uint `json:"student_id"` Student interface{} `json:"student"` ClassID uint `json:"class_id"` Class interface{} `json:"class"` Vision VisionData `json:"vision"` FatigueScore float64 `json:"fatigue_score"` AlertLevel string `json:"alert_level"` DetectionTime time.Time `json:"detection_time"` CreatedAt time.Time `json:"created_at"` } // NewDetectionService 创建检测服务 func NewDetectionService(db *gorm.DB) *DetectionService { return &DetectionService{DB: db} } // StartDetection 发起检测 func (s *DetectionService) StartDetection(c *gin.Context) { var req StartDetectionRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "code": 400, "message": "参数错误: " + err.Error(), }) return } // 创建检测任务 task := map[string]interface{}{ "task_no": generateTaskNo(), // 生成任务编号 "class_id": req.ClassID, "teacher_id": req.TeacherID, "student_count": req.StudentCount, "detection_type": req.DetectionType, "start_time": req.StartTime, "status": 0, // 0:进行中 } result := s.DB.Table("detection_tasks").Create(task) if result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{ "code": 500, "message": "发起检测失败: " + result.Error.Error(), }) return } // 返回响应 resp := StartDetectionResponse{ Code: 0, Message: "检测任务已创建", } resp.Data.TaskID = "task_" + string(rune(result.RowsAffected)) // 简化处理 resp.Data.TaskNo = task["task_no"].(string) resp.Data.StartTime = time.Now() c.JSON(http.StatusOK, resp) } // SubmitDetection 提交检测结果 func (s *DetectionService) SubmitDetection(c *gin.Context) { var req SubmitDetectionRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "code": 400, "message": "参数错误: " + err.Error(), }) return } // 创建检测记录 detection := map[string]interface{}{ "task_id": req.DetectionID, // 这里应该是task_id而不是detection_id "student_id": req.StudentID, "detection_time": time.Now(), "vision_left": req.Vision.VisionLeft, "vision_right": req.Vision.VisionRight, "fatigue_score": req.Response.Accuracy, // 使用响应准确率作为疲劳分数示例 "device_id": req.DeviceID, "status": 1, } result := s.DB.Table("detections").Create(detection) if result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{ "code": 500, "message": "提交检测结果失败: " + result.Error.Error(), }) return } resp := SubmitDetectionResponse{ Code: 0, Message: "检测结果提交成功", } resp.Data.ID = "detection_" + string(rune(result.RowsAffected)) c.JSON(http.StatusOK, resp) } // GetDetectionReport 获取检测报告 func (s *DetectionService) GetDetectionReport(c *gin.Context) { var req GetDetectionReportRequest if err := c.ShouldBindUri(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "code": 400, "message": "参数错误: " + err.Error(), }) return } // 查询检测报告 var report DetectionReport result := s.DB.Table("detection_reports").Where("detection_id = ? AND student_id = ?", req.DetectionID, req.StudentID).First(&report) if result.Error != nil { if result.Error == gorm.ErrRecordNotFound { c.JSON(http.StatusNotFound, gin.H{ "code": 404, "message": "检测报告不存在", }) return } c.JSON(http.StatusInternalServerError, gin.H{ "code": 500, "message": "查询检测报告失败: " + result.Error.Error(), }) return } resp := GetDetectionReportResponse{ Code: 0, Message: "获取成功", Data: report, } c.JSON(http.StatusOK, resp) } // GetDetectionHistory 获取检测历史 func (s *DetectionService) GetDetectionHistory(c *gin.Context) { var req GetDetectionHistoryRequest if err := c.ShouldBindQuery(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "code": 400, "message": "参数错误: " + err.Error(), }) return } // 构建查询条件 query := s.DB.Table("detection_history") if req.StudentID != 0 { query = query.Where("student_id = ?", req.StudentID) } if req.ClassID != 0 { query = query.Where("class_id = ?", req.ClassID) } if !req.StartDate.IsZero() { query = query.Where("detection_time >= ?", req.StartDate) } if !req.EndDate.IsZero() { query = query.Where("detection_time <= ?", req.EndDate) } // 查询总数 var total int64 query.Count(&total) // 查询数据 var histories []DetectionHistory query.Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Find(&histories) resp := GetDetectionHistoryResponse{ Code: 0, Message: "获取成功", } resp.Data.Items = histories resp.Data.Total = int(total) resp.Data.Page = req.Page c.JSON(http.StatusOK, resp) } // GetClassStats 获取班级统计 func (s *DetectionService) GetClassStats(c *gin.Context) { var req GetClassStatsRequest if err := c.ShouldBindUri(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "code": 400, "message": "参数错误: " + err.Error(), }) return } // 获取班级信息 var classInfo struct { ID uint `json:"id"` Name string `json:"name"` } s.DB.Table("classes").Select("id, name").Where("id = ?", req.ClassID).First(&classInfo) // 计算统计信息 var stats ClassStats stats.ClassID = req.ClassID stats.ClassName = classInfo.Name // 统计学生总数 var totalStudents int64 s.DB.Table("students").Where("class_id = ?", req.ClassID).Count(&totalStudents) stats.TotalStudents = int(totalStudents) // 统计参与检测的学生数 var testedStudents int64 s.DB.Table("detections"). Joins("JOIN detection_tasks ON detections.task_id = detection_tasks.id"). Where("detection_tasks.class_id = ?", req.ClassID). Distinct("student_id").Count(&testedStudents) stats.TestedStudents = int(testedStudents) // 计算平均视力 var resultAvg struct { AvgLeft float64 `json:"avg_left"` AvgRight float64 `json:"avg_right"` } s.DB.Table("detections"). Joins("JOIN detection_tasks ON detections.task_id = detection_tasks.id"). Where("detection_tasks.class_id = ?", req.ClassID). Select("AVG(vision_left) as avg_left, AVG(vision_right) as avg_right"). Scan(&resultAvg) stats.AvgVisionLeft = resultAvg.AvgLeft stats.AvgVisionRight = resultAvg.AvgRight // 统计预警数量 var alertCount int64 s.DB.Table("alerts"). Joins("JOIN students ON alerts.student_id = students.id"). Where("students.class_id = ?", req.ClassID). Count(&alertCount) stats.AlertCount = int(alertCount) // 预警分布 alertDist := make(map[string]int) alertDist["green"] = 0 // 示例数据 alertDist["yellow"] = 0 alertDist["orange"] = 0 alertDist["red"] = 0 stats.AlertDistribution = alertDist stats.CreatedAt = time.Now() resp := GetClassStatsResponse{ Code: 0, Message: "获取成功", Data: stats, } c.JSON(http.StatusOK, resp) } // generateTaskNo 生成任务编号 - 使用更安全的随机ID func generateTaskNo() string { // 生成随机ID b := make([]byte, 8) _, err := rand.Read(b) if err != nil { // 如果随机数生成失败,使用时间戳+简单随机数作为备用 return fmt.Sprintf("task_%d_%x", time.Now().UnixNano(), b[:4]) } randomID := hex.EncodeToString(b) return fmt.Sprintf("task_%s_%s", time.Now().Format("20060102_150405"), randomID[:8]) }