Version: 0.1.3.dev.260208
refactor: ♻️ 重命名部分接口接收器以避免与 dao 层包名冲突 - 调整部分接口接收器命名,避免与 dao 层包名重名 🧩 feat: 📅 新增获取用户今日日程接口并完成实现 fix: 🐛 修复现实日期与相对日期转换逻辑中的初始化时序问题 - 修复 conv/time.go 中日期转换函数的一个 bug ⏱️ - 解决 viper 在包级变量初始化时机过早的问题 - 避免因过早初始化导致无法读取配置中的学期开学/结束时间 📆
This commit is contained in:
@@ -3,6 +3,7 @@ package api
|
||||
type ApiHandlers struct {
|
||||
UserHandler *UserHandler
|
||||
TaskHandler *TaskHandler
|
||||
ScheduleHandler *CourseHandler
|
||||
CourseHandler *CourseHandler
|
||||
TaskClassHandler *TaskClassHandler
|
||||
ScheduleHandler *ScheduleAPI
|
||||
}
|
||||
|
||||
44
backend/api/schedule.go
Normal file
44
backend/api/schedule.go
Normal file
@@ -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))
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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" #学期结束日期,一定要设定为周日,确保最后一周完整
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user