diff --git a/backend/api/container.go b/backend/api/container.go index 3e757f5..8466a59 100644 --- a/backend/api/container.go +++ b/backend/api/container.go @@ -1,6 +1,7 @@ package api type ApiHandlers struct { - UserHandler *UserHandler - TaskHandler *TaskHandler + UserHandler *UserHandler + TaskHandler *TaskHandler + ScheduleHandler *ScheduleHandler } diff --git a/backend/api/schedule.go b/backend/api/schedule.go new file mode 100644 index 0000000..50fd628 --- /dev/null +++ b/backend/api/schedule.go @@ -0,0 +1,66 @@ +package api + +import ( + "errors" + "net/http" + + "github.com/LoveLosita/smartflow/backend/model" + "github.com/LoveLosita/smartflow/backend/respond" + "github.com/LoveLosita/smartflow/backend/service" + "github.com/gin-gonic/gin" +) + +type ScheduleHandler struct { + // 伸出手:准备接住 Service + service *service.ScheduleService +} + +// NewScheduleHandler 创建 ScheduleHandler 实例 +func NewScheduleHandler(service *service.ScheduleService) *ScheduleHandler { + return &ScheduleHandler{ + service: service, + } +} + +func (sa *ScheduleHandler) CheckUserCourse(c *gin.Context) { + //1.从请求中获取课程信息 + var req model.UserCheckCourseRequest + err := c.ShouldBindJSON(&req) + if err != nil { + c.JSON(http.StatusBadRequest, respond.WrongParamType) + return + } + //2.调用 service 层的 CheckSingleCourse 方法进行校验 + result := service.CheckSingleCourse(req) + //3.根据校验结果返回响应 + if result { + c.JSON(http.StatusOK, respond.Ok) + } else { + c.JSON(http.StatusBadRequest, respond.WrongCourseInfo) + } +} + +func (sa *ScheduleHandler) AddUserCourses(c *gin.Context) { + //1.从请求中获取课程信息 + var req model.UserImportCoursesRequest + err := c.ShouldBindJSON(&req) + if err != nil { + c.JSON(http.StatusBadRequest, respond.WrongParamType) + return + } + //2.从上下文获取用户ID + userIDInterface := c.GetInt("user_id") + //3.调用 service 层的 AddUserCourses 方法添加课程 + err = sa.service.AddUserCourses(req, userIDInterface) + if err != nil { + switch { + case errors.Is(err, respond.WrongParamType), errors.Is(err, respond.WrongCourseInfo): + c.JSON(http.StatusBadRequest, err) + default: + c.JSON(http.StatusInternalServerError, respond.InternalError(err)) + } + return + } + //4.返回成功响应 + c.JSON(http.StatusOK, respond.Ok) +} diff --git a/backend/cmd/start.go b/backend/cmd/start.go index c6ee81d..9d2af27 100644 --- a/backend/cmd/start.go +++ b/backend/cmd/start.go @@ -43,16 +43,20 @@ func Start() { userRepo := dao.NewUserDAO(db) cacheRepo := dao.NewCacheDAO(rdb) taskRepo := dao.NewTaskDAO(db) + scheduleRepo := dao.NewScheduleDAO(db) //service 层 userService := service.NewUserService(userRepo, cacheRepo) taskSv := service.NewTaskService(taskRepo) + scheduleService := service.NewScheduleService(scheduleRepo) //api 层 userApi := api.NewUserHandler(userService) taskApi := api.NewTaskHandler(taskSv) + scheduleApi := api.NewScheduleHandler(scheduleService) handlers := &api.ApiHandlers{ - UserHandler: userApi, - TaskHandler: taskApi, + UserHandler: userApi, + TaskHandler: taskApi, + ScheduleHandler: scheduleApi, } r := routers.RegisterRouters(handlers, cacheRepo) routers.StartEngine(r) diff --git a/backend/dao/schedule.go b/backend/dao/schedule.go new file mode 100644 index 0000000..0764e25 --- /dev/null +++ b/backend/dao/schedule.go @@ -0,0 +1,24 @@ +package dao + +import ( + "github.com/LoveLosita/smartflow/backend/model" + "gorm.io/gorm" +) + +type ScheduleDAO struct { + db *gorm.DB +} + +// NewScheduleDAO 创建ScheduleDAO实例 +func NewScheduleDAO(db *gorm.DB) *ScheduleDAO { + return &ScheduleDAO{ + db: db, + } +} + +func (dao *ScheduleDAO) AddUserCourses(courses []model.Schedule) error { + if err := dao.db.Create(&courses).Error; err != nil { + return err + } + return nil +} diff --git a/backend/model/schedule.go b/backend/model/schedule.go new file mode 100644 index 0000000..18967c5 --- /dev/null +++ b/backend/model/schedule.go @@ -0,0 +1,31 @@ +package model + +type Schedule struct { + ID int `gorm:"primaryKey;autoIncrement" json:"id"` + UserID int `gorm:"column:user_id;index" json:"user_id"` + Type string `gorm:"type:enum('course','task');comment:'course / task'" json:"type"` + RelID int `gorm:"column:rel_id;comment:'关联 course_id 或 task_item_id'" json:"rel_id"` + CanBeEmbedded bool `gorm:"column:can_be_embedded;comment:'是否允许嵌入水课'" json:"can_be_embedded"` + EmbeddedTaskID *uint `gorm:"column:embedded_task_id;comment:'若为水课嵌入,记录任务ID'" json:"embedded_task_id"` + Week int `gorm:"column:week" json:"week"` + DayOfWeek int `gorm:"column:day_of_week" json:"day_of_week"` + Sections string `gorm:"type:varchar(255)" json:"sections"` + Status string `gorm:"type:enum('normal','interrupted');default:'normal'" json:"status"` +} + +type UserImportCoursesRequest struct { + Courses []UserCheckCourseRequest `json:"courses"` +} + +type UserCheckCourseRequest struct { + CourseName string `json:"course_name"` + Location string `json:"location"` + IsAllowTasks bool `json:"is_allow_tasks"` + Arrangements []struct { + StartWeek int `json:"start_week"` + EndWeek int `json:"end_week"` + DayOfWeek int `json:"day_of_week"` + StartSection int `json:"start_section"` + EndSection int `json:"end_section"` + } `json:"arrangements"` +} diff --git a/backend/respond/respond.go b/backend/respond/respond.go index 1ae8f95..a212e14 100644 --- a/backend/respond/respond.go +++ b/backend/respond/respond.go @@ -133,4 +133,9 @@ var ( //请求相关的响应 Status: "40018", Info: "invalid priority", } + + WrongCourseInfo = Response{ //课程信息错误 + Status: "40019", + Info: "wrong course info", + } ) diff --git a/backend/routers/routers.go b/backend/routers/routers.go index ca2cde2..190802e 100644 --- a/backend/routers/routers.go +++ b/backend/routers/routers.go @@ -54,6 +54,12 @@ func RegisterRouters(handlers *api.ApiHandlers, cache *dao.CacheDAO) *gin.Engine taskGroup.POST("/create", handlers.TaskHandler.AddTask) taskGroup.GET("/get", handlers.TaskHandler.GetUserTasks) } + scheduleGroup := apiGroup.Group("/schedule") + { + scheduleGroup.Use(middleware.JWTTokenAuth(cache)) + scheduleGroup.POST("/validate", handlers.ScheduleHandler.CheckUserCourse) + scheduleGroup.POST("/import-courses", handlers.ScheduleHandler.AddUserCourses) + } } // 初始化Gin引擎 log.Println("Routes setup completed") diff --git a/backend/service/schedule.go b/backend/service/schedule.go new file mode 100644 index 0000000..fb13c77 --- /dev/null +++ b/backend/service/schedule.go @@ -0,0 +1,71 @@ +package service + +import ( + "fmt" + + "github.com/LoveLosita/smartflow/backend/dao" + "github.com/LoveLosita/smartflow/backend/model" + "github.com/LoveLosita/smartflow/backend/respond" +) + +type ScheduleService struct { + // 伸出手:准备接住 DAO + dao *dao.ScheduleDAO +} + +// NewScheduleService 创建 ScheduleService 实例 +func NewScheduleService(dao *dao.ScheduleDAO) *ScheduleService { + return &ScheduleService{ + dao: dao, + } +} + +func CheckSingleCourse(req model.UserCheckCourseRequest) bool { + for _, arrangement := range req.Arrangements { + if arrangement.StartWeek > arrangement.EndWeek || + arrangement.DayOfWeek < 1 || arrangement.DayOfWeek > 7 || + arrangement.StartSection < 1 || arrangement.EndSection < arrangement.StartSection || + arrangement.EndSection > 12 || arrangement.StartWeek < 1 || arrangement.EndWeek > 24 { + return false + } + } + return true +} + +// AddUserCourses 添加用户课程表 +func (ss *ScheduleService) AddUserCourses(req model.UserImportCoursesRequest, userID int) error { + //1.先校验参数是否正确 + for _, course := range req.Courses { + result := CheckSingleCourse(course) + if !result { + return respond.WrongCourseInfo + } + } + //2.转换为 Schedule 切片 + for _, course := range req.Courses { + var schedules []model.Schedule + for _, arrangement := range course.Arrangements { + for week := arrangement.StartWeek; week <= arrangement.EndWeek; week++ { + sections := fmt.Sprintf("%d-%d", arrangement.StartSection, arrangement.EndSection) + schedule := model.Schedule{ + Type: "course", + Week: week, + DayOfWeek: arrangement.DayOfWeek, + Sections: sections, + Status: "normal", + UserID: userID, + CanBeEmbedded: course.IsAllowTasks, + } + schedules = append(schedules, schedule) + } + } + //3.调用 DAO 方法添加课程 + err := ss.dao.AddUserCourses(schedules) + if err != nil { + return err + } + } + + //4.返回结果 + return nil +}