package conv import ( "fmt" "time" "github.com/LoveLosita/smartflow/backend/model" newagenttools "github.com/LoveLosita/smartflow/backend/newAgent/tools" ) // ScheduleStateToPreview 将 newAgent 的 ScheduleState 转换为前端预览缓存格式。 // // 职责边界: // 1. 只做数据格式转换,不做业务逻辑; // 2. 将每个 ScheduleTask 的每个 TaskSlot 转为一条 HybridScheduleEntry; // 3. Day → (Week, DayOfWeek) 通过 ScheduleState.DayToWeekDay 转换; // 4. 转换失败的 slot(day_index 无效)静默跳过。 func ScheduleStateToPreview( state *newagenttools.ScheduleState, userID int, conversationID string, taskClassIDs []int, summary string, ) *model.SchedulePlanPreviewCache { if state == nil { return nil } entries := make([]model.HybridScheduleEntry, 0, len(state.Tasks)) for i := range state.Tasks { t := &state.Tasks[i] // 待安排且无位置的任务不生成 entry。 if t.Status == "pending" && len(t.Slots) == 0 { continue } for _, slot := range t.Slots { week, dayOfWeek, ok := state.DayToWeekDay(slot.Day) if !ok { continue } entry := model.HybridScheduleEntry{ Week: week, DayOfWeek: dayOfWeek, SectionFrom: slot.SlotStart, SectionTo: slot.SlotEnd, Name: t.Name, } // Type 映射。 if t.Source == "event" { if t.EventType != "" { entry.Type = t.EventType } else { entry.Type = "course" } } else { entry.Type = "task" } // Status 映射:existing 不变,pending(有位置)= suggested。 if shouldMarkSuggestedInPreview(*t) { entry.Status = "suggested" } else { entry.Status = "existing" } // ID 映射。 if t.Source == "event" { entry.EventID = t.SourceID } else { entry.TaskItemID = t.SourceID } // 嵌入与阻塞语义。 entry.CanBeEmbedded = t.CanEmbed if t.Source == "event" && t.CanEmbed && t.EmbeddedBy == nil { // 可嵌入且当前无嵌入任务 → 不阻塞 suggested 占位。 entry.BlockForSuggested = false } else { entry.BlockForSuggested = true } entries = append(entries, entry) } } // 生成摘要(若调用方未提供)。 if summary == "" { existingCount := 0 suggestedCount := 0 for _, e := range entries { if e.Status == "existing" { existingCount++ } else { suggestedCount++ } } summary = fmt.Sprintf("共 %d 个日程条目,其中已确定 %d 个,新安排 %d 个。", len(entries), existingCount, suggestedCount) } return &model.SchedulePlanPreviewCache{ UserID: userID, ConversationID: conversationID, Summary: summary, HybridEntries: entries, TaskClassIDs: taskClassIDs, GeneratedAt: time.Now(), } } // shouldMarkSuggestedInPreview 判断某条 ScheduleTask 在预览层是否应标记为 suggested。 // // 规则说明: // 1. pending 任务在预览语义中属于“建议态”; // 2. source=task_item 且 Duration>0 的任务来自待排任务池, // 即使工具层在 place 后把它改成 existing,预览层也要继续按 suggested 输出。 func shouldMarkSuggestedInPreview(t newagenttools.ScheduleTask) bool { if t.Status == "pending" { return true } if t.Source == "task_item" && t.Duration > 0 { return true } return false }