Files
2024-11-11 10:57:15 +08:00

403 lines
12 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}