feat: 🗓️ 新增任务块排期能力并完善课程与日程模型
Version: 0.1.1.dev.260207 - 新增并测试通过将任务块排进日程接口 ✅ - 批量导入课程接口增加单双周功能,支持只在单双周上课的课程 📚 - 任务块时间定位逻辑调整为「第几周-周几」模式 🧭 refactor: 🔨 重构时间与日程数据结构 - 完成绝对日期与相对时间的转换逻辑 🔄 - 后续可根据需求灵活决定时间的传入与输出类型 - 再次重构 schedule 表单结构 - 拆分为 schedule_event(单)与 schedule(多) - 建立前者对后者的一对多关系 🧩 fix: 🐛 大幅调整表结构与业务逻辑,修复大量历史遗留 bug 🔥
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/LoveLosita/smartflow/backend/conv"
|
||||
"github.com/LoveLosita/smartflow/backend/dao"
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
"github.com/LoveLosita/smartflow/backend/respond"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
@@ -15,12 +16,14 @@ type TaskClassService struct {
|
||||
// 这里可以添加数据库连接或其他依赖
|
||||
taskClassRepo *dao.TaskClassDAO
|
||||
cacheRepo *dao.CacheDAO
|
||||
scheduleRepo *dao.ScheduleDAO
|
||||
}
|
||||
|
||||
func NewTaskClassService(taskClassRepo *dao.TaskClassDAO, cacheRepo *dao.CacheDAO) *TaskClassService {
|
||||
func NewTaskClassService(taskClassRepo *dao.TaskClassDAO, cacheRepo *dao.CacheDAO, scheduleRepo *dao.ScheduleDAO) *TaskClassService {
|
||||
return &TaskClassService{
|
||||
taskClassRepo: taskClassRepo,
|
||||
cacheRepo: cacheRepo,
|
||||
scheduleRepo: scheduleRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,3 +99,104 @@ func (sv *TaskClassService) GetUserCompleteTaskClass(ctx context.Context, userID
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (sv *TaskClassService) AddTaskClassItemIntoSchedule(ctx context.Context, req *model.UserInsertTaskClassItemToScheduleRequest, userID int, taskID int) error {
|
||||
//1.先验证任务块归属
|
||||
taskClassID, err := sv.taskClassRepo.GetTaskClassIDByTaskItemID(ctx, taskID) //通过任务块ID获取所属任务类ID
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ownerID, err := sv.taskClassRepo.GetTaskClassUserIDByID(ctx, taskClassID) //通过任务类ID获取所属用户ID
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ownerID != userID {
|
||||
return respond.TaskClassItemNotBelongToUser
|
||||
}
|
||||
//2.取出任务块信息
|
||||
taskItem, err := sv.taskClassRepo.GetTaskClassItemByID(ctx, taskID) //通过任务块ID获取任务块信息
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//更新TaskClassItem的embedded_time字段
|
||||
taskItem.EmbeddedTime = &model.TargetTime{
|
||||
DayOfWeek: req.DayOfWeek,
|
||||
Week: req.Week,
|
||||
SectionFrom: req.StartSection,
|
||||
SectionTo: req.EndSection,
|
||||
}
|
||||
//3.判断是否嵌入课程
|
||||
if req.EmbedCourseEventID != 0 {
|
||||
//先检查看课程是否存在、是否归属该用户以及是否已经被嵌入了其他任务块
|
||||
courseOwnerID, err := sv.scheduleRepo.GetCourseUserIDByID(ctx, req.EmbedCourseEventID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if courseOwnerID != userID {
|
||||
return respond.CourseNotBelongToUser
|
||||
}
|
||||
//再检查用户给的时间是否和课程的时间匹配(目前逻辑是给的区间必须完全匹配)
|
||||
match, err := sv.scheduleRepo.IsCourseTimeMatch(ctx, req.EmbedCourseEventID, req.Week, req.DayOfWeek, req.StartSection, req.EndSection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !match {
|
||||
return respond.CourseTimeNotMatch
|
||||
}
|
||||
//查询对应时段的课程是否已被其他任务块嵌入了(目前业务限制:一个课程只能被一个任务块嵌入,但是目前设计是支持多个任务块嵌入一节课的,只要放得下)
|
||||
isEmbedded, err := sv.scheduleRepo.IsCourseEmbeddedByOtherTaskBlock(ctx, req.EmbedCourseEventID, req.StartSection, req.EndSection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isEmbedded {
|
||||
return respond.CourseAlreadyEmbeddedByOtherTaskBlock
|
||||
}
|
||||
//嵌入课程,直接更新日程表对应时段的 embedded_task_id 字段
|
||||
err = sv.scheduleRepo.EmbedTaskIntoSchedule(req.StartSection, req.EndSection, req.DayOfWeek, req.Week, userID, taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//更新任务块的 embedded_time 字段
|
||||
err = sv.taskClassRepo.UpdateTaskClassItemEmbeddedTime(ctx, taskID, taskItem.EmbeddedTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
//4.否则构造Schedule模型
|
||||
sections := make([]int, 0, req.EndSection-req.StartSection+1)
|
||||
schedules, scheduleEvent := conv.UserInsertTaskItemRequestToModel(req, taskItem, taskID, userID, req.StartSection, req.EndSection)
|
||||
//4.1 统一检查冲突(避免逐条查库)
|
||||
conflict, err := sv.scheduleRepo.HasUserScheduleConflict(ctx, userID, req.Week, req.DayOfWeek, sections)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if conflict {
|
||||
return respond.ScheduleConflict
|
||||
}
|
||||
//5.写入数据库(事务)
|
||||
if err := sv.taskClassRepo.Transaction(func(txDAO *dao.TaskClassDAO) error {
|
||||
//5.1 先将任务块插入scheduleEvent表,获取生成的ID后再插入schedule表(因为schedule表有外键关联)
|
||||
id, err := sv.scheduleRepo.AddScheduleEvent(scheduleEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//5.2 将生成的 ScheduleEvent ID 赋值给对应的 Schedule 的 EventID 字段
|
||||
for i := range schedules {
|
||||
schedules[i].EventID = id
|
||||
}
|
||||
//5.3 插入 Schedule 表
|
||||
_, err = sv.scheduleRepo.AddSchedules(schedules)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//5.4 更新任务块的 embedded_time 字段
|
||||
if err := txDAO.UpdateTaskClassItemEmbeddedTime(ctx, taskID, taskItem.EmbeddedTime); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user