From 79b6be5f40ecd3642d11685f8ef1c43d3f3a3f2d Mon Sep 17 00:00:00 2001 From: LoveLosita <2810873701@qq.com> Date: Sun, 8 Feb 2026 19:09:40 +0800 Subject: [PATCH] =?UTF-8?q?Version:=200.1.3.dev.260208=20refactor:=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E9=87=8D=E5=91=BD=E5=90=8D=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=8E=A5=E5=8F=A3=E6=8E=A5=E6=94=B6=E5=99=A8=E4=BB=A5?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E4=B8=8E=20dao=20=E5=B1=82=E5=8C=85=E5=90=8D?= =?UTF-8?q?=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整部分接口接收器命名,避免与 dao 层包名重名 🧩 feat: 📅 新增获取用户今日日程接口并完成实现 fix: 🐛 修复现实日期与相对日期转换逻辑中的初始化时序问题 - 修复 conv/time.go 中日期转换函数的一个 bug ⏱️ - 解决 viper 在包级变量初始化时机过早的问题 - 避免因过早初始化导致无法读取配置中的学期开学/结束时间 📆 --- backend/api/container.go | 3 +- backend/api/schedule.go | 44 ++++++++ backend/cmd/start.go | 5 +- backend/config.yaml | 4 +- backend/conv/schedule.go | 200 ++++++++++++++++++++++++++++++++++++ backend/conv/time.go | 19 ++-- backend/dao/course.go | 12 +-- backend/dao/schedule.go | 18 ++++ backend/dao/user.go | 25 +++-- backend/model/schedule.go | 29 +++++- backend/routers/routers.go | 9 +- backend/service/schedule.go | 51 +++++++++ 12 files changed, 391 insertions(+), 28 deletions(-) create mode 100644 backend/api/schedule.go diff --git a/backend/api/container.go b/backend/api/container.go index e4b0046..944b5f7 100644 --- a/backend/api/container.go +++ b/backend/api/container.go @@ -3,6 +3,7 @@ package api type ApiHandlers struct { UserHandler *UserHandler TaskHandler *TaskHandler - ScheduleHandler *CourseHandler + CourseHandler *CourseHandler TaskClassHandler *TaskClassHandler + ScheduleHandler *ScheduleAPI } diff --git a/backend/api/schedule.go b/backend/api/schedule.go new file mode 100644 index 0000000..89d01d5 --- /dev/null +++ b/backend/api/schedule.go @@ -0,0 +1,44 @@ +package api + +import ( + "context" + "errors" + "net/http" + "time" + + "github.com/LoveLosita/smartflow/backend/respond" + "github.com/LoveLosita/smartflow/backend/service" + "github.com/gin-gonic/gin" +) + +type ScheduleAPI struct { + scheduleService *service.ScheduleService +} + +func NewScheduleAPI(scheduleService *service.ScheduleService) *ScheduleAPI { + return &ScheduleAPI{ + scheduleService: scheduleService, + } +} + +func (s *ScheduleAPI) GetUserTodaySchedule(c *gin.Context) { + // 1. 从请求上下文中获取用户ID + userID := c.GetInt("user_id") + //2.调用服务层方法获取用户当天的日程安排 + // 创建一个带 1 秒超时的上下文 + ctx, cancel := context.WithTimeout(c.Request.Context(), 1*time.Second) + defer cancel() // 记得释放资源 + todaySchedules, err := s.scheduleService.GetUserTodaySchedule(ctx, userID) + if err != nil { + switch { + case errors.Is(err, respond.WrongUserID): + c.JSON(http.StatusBadRequest, respond.WrongUserID) + return + default: + c.JSON(http.StatusInternalServerError, respond.InternalError(err)) + return + } + } + //3.返回日程安排数据给前端 + c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, todaySchedules)) +} diff --git a/backend/cmd/start.go b/backend/cmd/start.go index c7dd499..90e790d 100644 --- a/backend/cmd/start.go +++ b/backend/cmd/start.go @@ -52,17 +52,20 @@ func Start() { taskSv := service.NewTaskService(taskRepo) courseService := service.NewCourseService(courseRepo, scheduleRepo) taskClassService := service.NewTaskClassService(taskClassRepo, cacheRepo, scheduleRepo, manager) + scheduleService := service.NewScheduleService(scheduleRepo, userRepo) //api 层 userApi := api.NewUserHandler(userService) taskApi := api.NewTaskHandler(taskSv) courseApi := api.NewCourseHandler(courseService) taskClassApi := api.NewTaskClassHandler(taskClassService) + scheduleApi := api.NewScheduleAPI(scheduleService) handlers := &api.ApiHandlers{ UserHandler: userApi, TaskHandler: taskApi, - ScheduleHandler: courseApi, TaskClassHandler: taskClassApi, + CourseHandler: courseApi, + ScheduleHandler: scheduleApi, } r := routers.RegisterRouters(handlers, cacheRepo) routers.StartEngine(r) diff --git a/backend/config.yaml b/backend/config.yaml index 20193b6..1833183 100644 --- a/backend/config.yaml +++ b/backend/config.yaml @@ -34,6 +34,6 @@ redis: time: zone: "Asia/Shanghai" - semesterStartDate: "2024-09-09" #学期开始日期,一定要设定为周一,以便于计算周数 - semesterEndDate: "2025-01-20" #学期结束日期,一定要设定为周日,确保最后一周完整 + semesterStartDate: "2026-03-02" #学期开始日期,一定要设定为周一,以便于计算周数 + semesterEndDate: "2026-06-30" #学期结束日期,一定要设定为周日,确保最后一周完整 diff --git a/backend/conv/schedule.go b/backend/conv/schedule.go index 69b4cbb..0177b0e 100644 --- a/backend/conv/schedule.go +++ b/backend/conv/schedule.go @@ -59,3 +59,203 @@ func SchedulesToScheduleConflictDetail(schedules []model.Schedule) []model.Sched return res } + +// SectionToTime 映射表:将原子节次转为起始/结束时间点 +// 此处以重邮为例 +var sectionTimeMap = map[int][2]string{ + 1: {"08:00", "08:45"}, 2: {"08:55", "09:40"}, + 3: {"10:15", "11:00"}, 4: {"11:10", "11:55"}, + 5: {"14:00", "14:45"}, 6: {"14:55", "15:40"}, + 7: {"16:15", "17:00"}, 8: {"17:10", "17:55"}, + 9: {"19:00", "19:45"}, 10: {"19:55", "20:40"}, + 11: {"20:50", "21:35"}, 12: {"21:45", "22:30"}, +} + +/*func SchedulesToUserTodaySchedule(schedules []model.Schedule) []model.UserTodaySchedule { + if len(schedules) == 0 { + return []model.UserTodaySchedule{} + } + + // 1. 按周次和星期进行第一层分组 (map[week][day]schedules) + // 虽然是“今日日程”,但传入的切片可能包含多天,这样写兼容性更好 + dayGroups := make(map[string][]model.Schedule) + for _, s := range schedules { + dayKey := fmt.Sprintf("%d-%d", s.Week, s.DayOfWeek) + dayGroups[dayKey] = append(dayGroups[dayKey], s) + } + + var result []model.UserTodaySchedule + + for _, daySchedules := range dayGroups { + todayDTO := model.UserTodaySchedule{ + Week: daySchedules[0].Week, + DayOfWeek: daySchedules[0].DayOfWeek, + Events: []model.EventBrief{}, + } + + // 2. 在每一天内部,按 EventID 进行第二层聚合(把连续的节次拼成一个 Event) + eventGroups := make(map[int][]model.Schedule) + for _, s := range daySchedules { + eventGroups[s.EventID] = append(eventGroups[s.EventID], s) + } + + // 3. 遍历每个 Event 组,转化为 EventBrief + var tempEvents []model.EventBrief + for eventID, slots := range eventGroups { + // 对当前 Event 的所有原子槽位按节次排序 + sort.Slice(slots, func(i, j int) bool { + return slots[i].Section < slots[j].Section + }) + + firstSlot := slots[0] + lastSlot := slots[len(slots)-1] + + brief := model.EventBrief{ + ID: eventID, + Name: firstSlot.Event.Name, + Location: *firstSlot.Event.Location, + Type: firstSlot.Event.Type, + StartTime: sectionTimeMap[firstSlot.Section][0], // 取第一节的开始时间 + EndTime: sectionTimeMap[lastSlot.Section][1], // 取最后一节的结束时间 + } + + // 💡 4. 检查是否有嵌入任务 (Embedded Task) + // 逻辑:只要这个时间块中任何一个原子槽位带了 EmbeddedTaskID,就提取它 + // 注意:这里假设你在 DAO 层也 Preload 了 Task 信息,或者在此处仅填 ID + for _, slot := range slots { + if slot.EmbeddedTaskID != nil { + brief.EmbeddedTaskInfo = model.TaskBrief{ + ID: *slot.EmbeddedTaskID, + Name: *slot.EmbeddedTask.Content, + Type: "task", + } + break // 找到一个即代表该块已占用 + } + } + + tempEvents = append(tempEvents, brief) + } + + // 5. 对结果进行排序(按开始时间),并分配 Order + sort.Slice(tempEvents, func(i, j int) bool { + return tempEvents[i].StartTime < tempEvents[j].StartTime + }) + + for i := range tempEvents { + tempEvents[i].Order = i + 1 + } + + todayDTO.Events = tempEvents + result = append(result, todayDTO) + } + + return result +}*/ + +func SchedulesToUserTodaySchedule(schedules []model.Schedule) []model.UserTodaySchedule { + if len(schedules) == 0 { + return []model.UserTodaySchedule{} + } + + // 1. 数据预处理:按 Week-Day 分组 + dayGroups := make(map[string][]model.Schedule) + for _, s := range schedules { + dayKey := fmt.Sprintf("%d-%d", s.Week, s.DayOfWeek) + dayGroups[dayKey] = append(dayGroups[dayKey], s) + } + + var result []model.UserTodaySchedule + + for _, daySchedules := range dayGroups { + todayDTO := model.UserTodaySchedule{ + Week: daySchedules[0].Week, + DayOfWeek: daySchedules[0].DayOfWeek, + Events: []model.EventBrief{}, + } + + // 💡 关键点:建立一个 Section 查找表,方便 O(1) 确定某节课是什么 + sectionMap := make(map[int]model.Schedule) + for _, s := range daySchedules { + sectionMap[s.Section] = s + } + + order := 1 + // 💡 线性扫描:从第 1 节巡检到第 12 节 + for curr := 1; curr <= 12; { + if slot, ok := sectionMap[curr]; ok { + // === A 场景:当前节次有课 === + + // 1. 寻找该事件的连续范围(比如 9-12 节连上) + // 我们向后探测,直到 EventID 变化或节次断开 + end := curr + for next := curr + 1; next <= 12; next++ { + if nextSlot, exist := sectionMap[next]; exist && nextSlot.EventID == slot.EventID { + end = next + } else { + break + } + } + + // 2. 封装 EventBrief + brief := model.EventBrief{ + ID: slot.EventID, + Order: order, + Name: slot.Event.Name, + Location: *slot.Event.Location, + Type: slot.Event.Type, + StartTime: sectionTimeMap[curr][0], + EndTime: sectionTimeMap[end][1], + Span: end - curr + 1, + } + + // 3. 处理嵌入任务 + // 只要这几个连续节次里有一个有任务,就带上 + for i := curr; i <= end; i++ { + if s, exist := sectionMap[i]; exist && s.EmbeddedTask != nil { + brief.EmbeddedTaskInfo = model.TaskBrief{ + ID: s.EmbeddedTask.ID, + Name: *s.EmbeddedTask.Content, + Type: "task", + } + break + } + } + + todayDTO.Events = append(todayDTO.Events, brief) + + // 💡 指针跳跃:直接跳过已处理的节次 + curr = end + 1 + order++ + + } else { + // === B 场景:当前节次没课(Type = "empty") === + + // 逻辑:按照学校标准大节(1-2, 3-4...)进行空位合并 + // 如果当前是奇数节(1, 3, 5...)且下一节也没课,就合并成一个空块 + emptyEnd := curr + if curr%2 != 0 && curr < 12 { + if _, nextHasClass := sectionMap[curr+1]; !nextHasClass { + emptyEnd = curr + 1 + } + } + + todayDTO.Events = append(todayDTO.Events, model.EventBrief{ + ID: 0, // 空课 ID 为 0 + Order: order, + Name: "无课", + Type: "empty", + StartTime: sectionTimeMap[curr][0], + EndTime: sectionTimeMap[emptyEnd][1], + Location: "休息时间", + }) + + curr = emptyEnd + 1 + order++ + } + } + + result = append(result, todayDTO) + } + + return result +} diff --git a/backend/conv/time.go b/backend/conv/time.go index f3b7a2a..d6da20d 100644 --- a/backend/conv/time.go +++ b/backend/conv/time.go @@ -11,19 +11,22 @@ import ( // DateFormat 此处定义基准学期的开始和结束日期 const DateFormat = "2006-01-02" -var ( - SemesterStartDate = viper.GetString("semesterStartDate") // 从配置文件中读取学期开始日期 - SemesterEndDate = viper.GetString("semesterEndDate") // 从配置文件中读取学期结束日期 -) - // RealDateToRelativeDate 将绝对日期转换为相对日期(格式: "week-day") func RealDateToRelativeDate(realDate string) (int, int, error) { + SemesterStartDate := viper.GetString("time.semesterStartDate") // 从配置文件中读取学期开始日期 + SemesterEndDate := viper.GetString("time.semesterEndDate") // 从配置文件中读取学期结束日期 t, err := time.Parse(DateFormat, realDate) if err != nil { return 0, 0, err } - start, _ := time.Parse(DateFormat, SemesterStartDate) - end, _ := time.Parse(DateFormat, SemesterEndDate) + start, err := time.Parse(DateFormat, SemesterStartDate) + if err != nil { + return 0, 0, err + } + end, err := time.Parse(DateFormat, SemesterEndDate) + if err != nil { + return 0, 0, err + } // 边界校验:日期必须在学期范围内 if t.Before(start) || t.After(end) { return 0, 0, errors.New("日期超出学期范围") @@ -39,6 +42,8 @@ func RealDateToRelativeDate(realDate string) (int, int, error) { // RelativeDateToRealDate 将相对日期转换为绝对日期(输入格式: "week-day") func RelativeDateToRealDate(week, dayOfWeek int) (string, error) { + SemesterStartDate := viper.GetString("time.semesterStartDate") // 从配置文件中读取学期开始日期 + SemesterEndDate := viper.GetString("time.semesterEndDate") // 从配置文件中读取学期结束日期 start, _ := time.Parse(DateFormat, SemesterStartDate) // 核心转换逻辑:(周-1)*7 + (天-1) offsetDays := (week-1)*7 + (dayOfWeek - 1) diff --git a/backend/dao/course.go b/backend/dao/course.go index 46cf308..d304926 100644 --- a/backend/dao/course.go +++ b/backend/dao/course.go @@ -22,15 +22,15 @@ func (r *CourseDAO) WithTx(tx *gorm.DB) *CourseDAO { return &CourseDAO{db: tx} } -func (dao *CourseDAO) AddUserCoursesIntoSchedule(ctx context.Context, courses []model.Schedule) error { - if err := dao.db.WithContext(ctx).Create(&courses).Error; err != nil { +func (r *CourseDAO) AddUserCoursesIntoSchedule(ctx context.Context, courses []model.Schedule) error { + if err := r.db.WithContext(ctx).Create(&courses).Error; err != nil { return err } return nil } -func (dao *CourseDAO) AddUserCoursesIntoScheduleEvents(ctx context.Context, events []model.ScheduleEvent) ([]int, error) { - if err := dao.db.WithContext(ctx).Create(&events).Error; err != nil { +func (r *CourseDAO) AddUserCoursesIntoScheduleEvents(ctx context.Context, events []model.ScheduleEvent) ([]int, error) { + if err := r.db.WithContext(ctx).Create(&events).Error; err != nil { return nil, err } ids := make([]int, 0, len(events)) @@ -43,8 +43,8 @@ func (dao *CourseDAO) AddUserCoursesIntoScheduleEvents(ctx context.Context, even // Transaction 在同一个数据库事务中执行传入的函数,供 service 层复用(自动提交/回滚) // 规则:fn 返回 nil \-\> 提交;fn 返回 error 或发生 panic \-\> 回滚 // 说明:gorm\.\(\\\*DB\)\.Transaction 会在 fn 返回 error 时回滚,并在发生 panic 时自动回滚后继续向上抛出 panic -func (dao *CourseDAO) Transaction(fn func(txDAO *CourseDAO) error) error { - return dao.db.Transaction(func(tx *gorm.DB) error { +func (r *CourseDAO) Transaction(fn func(txDAO *CourseDAO) error) error { + return r.db.Transaction(func(tx *gorm.DB) error { return fn(NewCourseDAO(tx)) }) } diff --git a/backend/dao/schedule.go b/backend/dao/schedule.go index f1a8a82..015959f 100644 --- a/backend/dao/schedule.go +++ b/backend/dao/schedule.go @@ -266,3 +266,21 @@ func (d *ScheduleDAO) GetNonCourseScheduleConflicts(ctx context.Context, newSche return fullConflicts, err } +func (d *ScheduleDAO) GetUserTodaySchedule(ctx context.Context, userID, week, dayOfWeek int) ([]model.Schedule, error) { + var schedules []model.Schedule + + // 1. Preload("Event"): 拿到课程/任务的基础信息(名、地、型) + // 2. Preload("EmbeddedTask"): 拿到“水课”里嵌入的具体任务详情 + err := d.db.WithContext(ctx). + Preload("Event"). + Preload("EmbeddedTask"). + Where("user_id = ? AND week = ? AND day_of_week = ?", userID, week, dayOfWeek). + Order("section ASC"). + Find(&schedules).Error + + if err != nil { + return nil, err + } + + return schedules, nil +} diff --git a/backend/dao/user.go b/backend/dao/user.go index 8af172e..31505fe 100644 --- a/backend/dao/user.go +++ b/backend/dao/user.go @@ -29,7 +29,7 @@ func (r *UserDAO) WithTx(tx *gorm.DB) *UserDAO { // Create 创建新用户 // 插入新用户信息到数据库 -func (dao *UserDAO) Create(username, phoneNumber, password string) (*model.User, error) { +func (r *UserDAO) Create(username, phoneNumber, password string) (*model.User, error) { // 创建User实例 user := &model.User{ Username: username, @@ -41,15 +41,15 @@ func (dao *UserDAO) Create(username, phoneNumber, password string) (*model.User, } // 插入数据 - if err := dao.db.Create(user).Error; err != nil { + if err := r.db.Create(user).Error; err != nil { return nil, err } return user, nil } -func (dao *UserDAO) IfUsernameExists(name string) (bool, error) { - err := dao.db.Where("username = ?", name).First(&model.User{}).Error +func (r *UserDAO) IfUsernameExists(name string) (bool, error) { + err := r.db.Where("username = ?", name).First(&model.User{}).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return false, nil @@ -59,20 +59,29 @@ func (dao *UserDAO) IfUsernameExists(name string) (bool, error) { return true, nil } -func (dao *UserDAO) GetUserHashedPasswordByName(name string) (string, error) { +func (r *UserDAO) GetUserHashedPasswordByName(name string) (string, error) { var user model.User - err := dao.db.Where("username = ?", name).First(&user).Error + err := r.db.Where("username = ?", name).First(&user).Error if err != nil { return "", err } return user.Password, nil } -func (dao *UserDAO) GetUserIDByName(name string) (int, error) { +func (r *UserDAO) GetUserIDByName(name string) (int, error) { var user model.User - err := dao.db.Where("username = ?", name).First(&user).Error + err := r.db.Where("username = ?", name).First(&user).Error if err != nil { return -1, err } return int(user.ID), nil } + +func (r *UserDAO) GetUserByID(id int) (*model.User, error) { + var user model.User + err := r.db.Where("id = ?", id).First(&user).Error + if err != nil { + return nil, err + } + return &user, nil +} diff --git a/backend/model/schedule.go b/backend/model/schedule.go index 33e4fb0..359c110 100644 --- a/backend/model/schedule.go +++ b/backend/model/schedule.go @@ -20,7 +20,8 @@ type Schedule struct { EmbeddedTaskID *int `gorm:"column:embedded_task_id;comment:若为水课嵌入,记录具体的任务项ID" json:"embedded_task_id"` Status string `gorm:"column:status;type:enum('normal','interrupted');default:'normal';comment:状态: 正常/因故中断" json:"status"` // 💡 必须加上这一行,告诉 GORM 如何关联元数据 - Event ScheduleEvent `gorm:"foreignKey:EventID" json:"event"` + Event ScheduleEvent `gorm:"foreignKey:EventID" json:"event"` + EmbeddedTask *TaskClassItem `gorm:"foreignKey:EmbeddedTaskID" json:"embedded_task"` } type ScheduleConflictDetail struct { @@ -41,6 +42,32 @@ type ScheduleEmbeddedTask struct { TaskID int `json:"task_id"` } +type UserTodaySchedule struct { + DayOfWeek int `json:"day_of_week"` + Week int `json:"week"` + Events []EventBrief `json:"events"` +} + +type EventBrief struct { + ID int `json:"id"` // 这个 ID 是 ScheduleEvent 的 ID,不是 Schedule 的 ID + Order int `json:"order"` // order 用于区分它们的显示顺序 + Name string `json:"name"` + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` + Location string `json:"location"` + Type string `json:"type"` + Span int `json:"span"` // 跨越的节数,给前端用来渲染宽度 + EmbeddedTaskInfo TaskBrief `json:"embedded_task_info,omitempty"` +} + +type TaskBrief struct { + ID int `json:"id"` // 这个 ID 是 ScheduleEvent 的 ID,不是 Schedule 的 ID + Name string `json:"name"` + /*StartTime string `json:"start_time"` + EndTime string `json:"end_time"`*/ + Type string `json:"type"` +} + func (ScheduleEvent) TableName() string { return "schedule_events" } func (Schedule) TableName() string { return "schedules" } diff --git a/backend/routers/routers.go b/backend/routers/routers.go index 0677967..14195ff 100644 --- a/backend/routers/routers.go +++ b/backend/routers/routers.go @@ -57,8 +57,8 @@ func RegisterRouters(handlers *api.ApiHandlers, cache *dao.CacheDAO) *gin.Engine courseGroup := apiGroup.Group("/course") { courseGroup.Use(middleware.JWTTokenAuth(cache)) - courseGroup.POST("/validate", handlers.ScheduleHandler.CheckUserCourse) - courseGroup.POST("/import", handlers.ScheduleHandler.AddUserCourses) + courseGroup.POST("/validate", handlers.CourseHandler.CheckUserCourse) + courseGroup.POST("/import", handlers.CourseHandler.AddUserCourses) } taskClassGroup := apiGroup.Group("/task-class") { @@ -69,6 +69,11 @@ func RegisterRouters(handlers *api.ApiHandlers, cache *dao.CacheDAO) *gin.Engine taskClassGroup.PUT("/update", handlers.TaskClassHandler.UserUpdateTaskClass) taskClassGroup.POST("/insert-into-schedule", handlers.TaskClassHandler.UserAddTaskClassItemIntoSchedule) } + scheduleGroup := apiGroup.Group("/schedule") + { + scheduleGroup.Use(middleware.JWTTokenAuth(cache)) + scheduleGroup.GET("/today", handlers.ScheduleHandler.GetUserTodaySchedule) + } } // 初始化Gin引擎 log.Println("Routes setup completed") diff --git a/backend/service/schedule.go b/backend/service/schedule.go index 6d43c33..1519795 100644 --- a/backend/service/schedule.go +++ b/backend/service/schedule.go @@ -1 +1,52 @@ package service + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/LoveLosita/smartflow/backend/conv" + "github.com/LoveLosita/smartflow/backend/dao" + "github.com/LoveLosita/smartflow/backend/respond" + "gorm.io/gorm" +) + +type ScheduleService struct { + scheduleDAO *dao.ScheduleDAO + userDAO *dao.UserDAO +} + +func NewScheduleService(scheduleDAO *dao.ScheduleDAO, userDAO *dao.UserDAO) *ScheduleService { + return &ScheduleService{ + scheduleDAO: scheduleDAO, + userDAO: userDAO, + } +} + +func (ss *ScheduleService) GetUserTodaySchedule(ctx context.Context, userID int) (interface{}, error) { + //1.先检查用户id是否存在 + _, err := ss.userDAO.GetUserByID(userID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, respond.WrongUserID + } + return nil, err + } + //2.获取当前日期 + curTime := time.Now().Format("2006-01-02") + /*curTime := "2026-03-02" //测试数据*/ + week, dayOfWeek, err := conv.RealDateToRelativeDate(curTime) + if err != nil { + return nil, err + } + fmt.Println(week, dayOfWeek) + //3.查询用户当天的日程安排 + schedules, err := ss.scheduleDAO.GetUserTodaySchedule(ctx, userID, week, dayOfWeek) //测试数据 + if err != nil { + return nil, err + } + //4.转换为前端需要的格式 + todaySchedules := conv.SchedulesToUserTodaySchedule(schedules) + return todaySchedules, nil +}