package utils import ( "fmt" "github.com/gin-gonic/gin" "github.com/google/uuid" "gorm.io/gorm" "net/http" "sort" "strconv" "sync" "time" "zhixiangtong/models" ) type Setting struct { StartDate string `json:"startDate"` TotalWeeks int `json:"totalWeeks"` EndDate string `json:"endDate"` TimeSetting []TimeSet `json:"timeSetting"` } // RemoveIntDuplicates 去重函数,去除整数切片中的重复元素 func RemoveIntDuplicates(elements []int) []int { seen := make(map[int]bool) var result []int for _, v := range elements { if _, ok := seen[v]; !ok { result = append(result, v) seen[v] = true } } return result } func RemoveStringDuplicates(stringSlice []string) []string { keys := make(map[string]bool) var list []string for _, entry := range stringSlice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list } // SetupRouter 配置Gin路由 func SetupRouter(db *gorm.DB, config *Config) *gin.Engine { r := gin.New() r.Use(CustomLogger()) // 处理跨域 r.Use(CORSMiddleware()) // 获取所有校区 r.GET("/getCampusList", func(c *gin.Context) { // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() var campuses []models.Campus if err := db.Find(&campuses).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "无法获取校区列表", "data": nil}) return } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功!", "data": campuses}) return }() wg.Wait() }) // 获取校区内所有教学楼 r.GET("/getBuilds/:id", func(c *gin.Context) { campusId := c.Param("id") if campusId == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,校区ID为必传项!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() var buildings []models.Building if err := db.Find(&buildings, "campus_id = ?", campusId).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"code": 500, "msg": "获取失败!", "data": nil}) return } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功!", "data": buildings}) return }() wg.Wait() }) // 获取说所有教学楼 r.GET("/getBuildList", func(c *gin.Context) { // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() var buildings []models.Building if err := db.Find(&buildings).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "无法获取教学楼列表", "data": nil}) return } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功!", "data": buildings}) return }() wg.Wait() }) // 获取教室列表 r.GET("/getClassroomList/:id", func(c *gin.Context) { buildId := c.Param("id") var classrooms []models.Classroom if buildId == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,教学楼ID为必传项!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() if result := db.Find(&classrooms, "build_id = ? ", buildId); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"code": 500, "msg": "获取失败!", "data": nil}) return } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功!", "data": classrooms}) return }() wg.Wait() }) // 获取校区班级列表 r.GET("/getCampusClass/:id", func(c *gin.Context) { var classNames []models.Classname campusId := c.Param("id") if campusId == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,校区ID为必传项!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() if result := db.Find(&classNames, "campus_id = ?", campusId); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"code": 500, "msg": "获取失败!", "data": nil}) return } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功!", "data": classNames}) return }() wg.Wait() }) // 获取班级课表 r.GET("/getCourse/:id", func(c *gin.Context) { var courses []models.Course classnameId := c.Param("id") if classnameId == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,班级ID为必传项!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() if result := db.Find(&courses, "classname_id = ? AND status = 1", classnameId); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"code": 422, "msg": "课程查询失败!", "data": nil}) return } // 按照课程名称、教室、星期几和上课时间去重 uniqueCourses := make(map[string]map[string]map[int][]models.Course) for _, course := range courses { if uniqueCourses[course.Course] == nil { uniqueCourses[course.Course] = make(map[string]map[int][]models.Course) } if uniqueCourses[course.Course][course.Classroom] == nil { uniqueCourses[course.Course][course.Classroom] = make(map[int][]models.Course) } uniqueCourses[course.Course][course.Classroom][course.Day] = append(uniqueCourses[course.Course][course.Classroom][course.Day], course) } var resultList []map[string]interface{} for courseName, classrooms := range uniqueCourses { for classroom, days := range classrooms { for day, courses := range days { var weeks []int for _, course := range courses { weeks = append(weeks, course.Week) } weeks = RemoveIntDuplicates(weeks) sort.Ints(weeks) var timeRange []int for _, t := range courses { timeRange = append(timeRange, t.ClassTime) } timeRange = RemoveIntDuplicates(timeRange) sort.Ints(timeRange) resultList = append(resultList, map[string]interface{}{ "id": uuid.New().String(), "course": courseName, "classroom": classroom, "teacher": courses[0].Teacher, "weeks": weeks, "day": day + 1, "time": timeRange, }) } } } // 返回结果 c.JSON(http.StatusOK, gin.H{ "code": 200, "msg": "获取成功!", "data": resultList, }) return }() wg.Wait() }) // 获取空闲教室 r.GET("/getEmptyClassroom", func(c *gin.Context) { // 获取请求参数 campusID := c.Query("campus_id") buildID := c.Query("build_id") // 可选参数 startStamp := c.Query("startStamp") endStamp := c.Query("endStamp") // 参数校验 if campusID == "" || startStamp == "" || endStamp == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,校区ID和时间戳为必传项!", "data": nil}) return } // 解析时间戳参数 startTimestamp, err := strconv.ParseInt(startStamp, 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "开始时间戳格式错误!", "data": nil}) return } endTimestamp, err := strconv.ParseInt(endStamp, 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "结束时间戳格式错误!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() // 查询有课的教室 classroom1 var classroom1 []string query := db.Model(&models.Course{}). Where("campus_id = ? AND startStamp >= ? AND endStamp <= ? AND status = 1", campusID, startTimestamp, endTimestamp) if buildID != "" { query = query.Where("build_id = ?", buildID) } err = query.Pluck("classroom_id", &classroom1).Error if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "查询课程数据失败!", "data": nil}) return } // 查询所有教室 classroom2,根据 campus_id 和可选的 build_id 过滤 var classroom2 []models.Classroom query = db.Where("campus_id = ?", campusID) if buildID != "" { query = query.Where("build_id = ?", buildID) } err = query.Find(&classroom2).Error if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "查询教室数据失败!", "data": nil}) return } // 使用一个 map 来判断 classroom1 中的教室是否有课 classroom1Set := make(map[string]bool) for _, id := range classroom1 { classroom1Set[id] = true } // 过滤掉有课的教室,得到无课教室列表 data var data []models.Classroom for _, classroom := range classroom2 { if !classroom1Set[classroom.ID] { data = append(data, classroom) } } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "查询成功!", "data": data}) return }() wg.Wait() }) // 获取教室课表 r.GET("/getClassroomCourses", func(c *gin.Context) { var courses []models.Course classroomID := c.Query("classroom_id") weekStr := c.Query("week") if classroomID == "" || weekStr == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,教室ID、周数为必传项!", "data": nil}) return } week, err := strconv.Atoi(weekStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 422, "msg": "参数错误,周数格式不正确!", "data": nil}) return } // 使用 WaitGroup 等待 Goroutine 完成 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 在 Goroutine 完成时调用 Done() // 根据 classroom_id 和时间范围筛选数据 if result := db.Where("classroom_id = ? AND week = ? AND status = 1", classroomID, week).Find(&courses); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "课程查询失败!", "data": nil}) return } // 按照 week, day 和 classTime 聚合 type AggregatedCourse struct { Week int `json:"week"` Day int `json:"day"` ClassTime int `json:"classTime"` Classnames []string `json:"classnames"` Campus string `json:"campus"` Build string `json:"build"` StartTime time.Time `json:"startTime"` EndTime time.Time `json:"endTime"` StartStamp float64 `json:"startStamp"` EndStamp float64 `json:"endStamp"` ClassRoom string `json:"classroom"` Course string `json:"course"` Teacher string `json:"teacher"` ID string `json:"id"` } aggregatedData := make(map[string]AggregatedCourse) for _, course := range courses { key := fmt.Sprintf("%d-%d-%d", course.Week, course.Day, course.ClassTime) if _, exists := aggregatedData[key]; !exists { aggregatedData[key] = AggregatedCourse{ Week: course.Week, Day: course.Day, ClassTime: course.ClassTime, Classnames: []string{}, Campus: course.Campus, Build: course.Build, StartStamp: course.StartStamp, EndStamp: course.EndStamp, StartTime: course.StartTime, EndTime: course.EndTime, ClassRoom: course.Classroom, Course: course.Course, Teacher: course.Teacher, ID: course.ID, } } aggCourse := aggregatedData[key] aggCourse.Classnames = append(aggCourse.Classnames, course.ClassName) aggregatedData[key] = aggCourse } var resultList []AggregatedCourse for _, aggCourse := range aggregatedData { // 去重课程名称 aggCourse.Classnames = RemoveStringDuplicates(aggCourse.Classnames) resultList = append(resultList, aggCourse) } // 返回聚合结果 c.JSON(http.StatusOK, gin.H{ "code": 200, "msg": "获取成功!", "data": resultList, }) return }() wg.Wait() }) // 获取学校配置 r.GET("/getTermSetting", func(c *gin.Context) { data := Setting{ TimeSetting: config.TimeSetting, StartDate: config.StartDate, EndDate: config.EndDate, TotalWeeks: config.TotalWeeks, } c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取成功", "data": data}) }) // 处理请求方法错 r.NoMethod(NotMethodHandler) // 处理无效路径 r.NoRoute(NotFoundHandler) return r }