Files
smartmate/backend/model/schedule.go
Losita 668af5f6c0 Version: 0.9.31.dev.260419
后端:
1. 日程暂存接口——前端拖拽调整后保存到 Redis 快照
  - api/agent.go:新增 SaveScheduleState handler,解析绝对时间格式请求体,3 秒超时保护
  - routers/routers.go:注册 POST /schedule-state
  - model/agent.go:新增 SaveScheduleStatePlacedItem / SaveScheduleStateRequest 结构体
  - respond/respond.go:新增 5 个排程状态错误码(40058~40062)
  - 新增 service/agentsvc/agent_schedule_state.go:Load 快照 → ApplyPlacedItems → Save 回 Redis,校验归属
  - 新增 newAgent/conv/schedule_state_apply.go:ApplyPlacedItems 绝对坐标→相对 day_index 转换,去重/坐标/嵌入关系校验
2. SchedulePersistor 持久化层全面下线
  - 删除 newAgent/conv/schedule_persist.go(280 行,DiffScheduleState → applyChange → 事务写库整条链路)
  - model/state_store.go:移除 SchedulePersistor 接口
  - model/graph_run_state.go / node/execute.go / node/agent_nodes.go / service/agent.go / service/agent_newagent.go /
  cmd/start.go:移除 SchedulePersistor 字段、参数、注入六处
3. schedule_completed 事件推送——deliver 节点排程完毕信号
  - model/common_state.go:新增 HasScheduleChanges 标记,ResetForNextRun 清理
  - node/execute.go / node/rough_build.go:写工具和粗排成功后置 HasScheduleChanges=true
  - node/deliver.go:IsCompleted && HasScheduleChanges 时调用 EmitScheduleCompleted
  - stream/emitter.go:新增 EmitScheduleCompleted 方法
  - stream/openai.go:新增 StreamExtraKindScheduleCompleted + NewScheduleCompletedExtra
4. 预览接口补全 task_class_id
  - model/agent.go:GetSchedulePlanPreviewResponse 新增 TaskClassIDs
  - model/schedule.go:HybridScheduleEntry 新增 TaskClassID
  - conv/schedule_preview.go / service/agent_schedule_preview.go / service/schedule.go:三处透传填充
前端:
5. 排程完毕卡片 + 精排弹窗集成
  - 新增 api/schedule_agent.ts:getSchedulePreview / saveScheduleState / applyBatchIntoSchedule
  - types/dashboard.ts:新增 HybridScheduleEntry / SchedulePreviewData / PlacedItem 类型
  - components/dashboard/AssistantPanel.vue:监听 schedule_completed 事件异步拉取排程渲染卡片,集成 ScheduleResultCard + ScheduleFineTuneModal;confirm 交互从文本消息改为 resume 协议(approve/reject/cancel)
6. ToolTracePrototypeView 原型页新增日程小卡片 + 拖拽编排弹窗演示
7. DashboardView import 区域尺寸微调
2026-04-19 13:53:07 +08:00

175 lines
8.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import "time"
type ScheduleEvent struct {
ID int `gorm:"primaryKey;autoIncrement" json:"id"`
UserID int `gorm:"column:user_id;index:idx_user_events;not null" json:"user_id"`
Name string `gorm:"column:name;type:varchar(255);not null;comment:课程或任务名称" json:"name"`
Location *string `gorm:"column:location;type:varchar(255);default:'';comment:地点 (教学楼/会议室)" json:"location"`
Type string `gorm:"column:type;type:enum('course','task');not null;comment:日程类型" json:"type"`
RelID *int `gorm:"column:rel_id;comment:关联原始数据ID (如教务系统的课程ID)" json:"rel_id"`
CanBeEmbedded bool `gorm:"column:can_be_embedded;not null;default:0;comment:是否允许在此时段嵌入其他任务" json:"can_be_embedded"`
StartTime time.Time `gorm:"column:start_time;type:time;comment:开始时间" json:"start_time"`
EndTime time.Time `gorm:"column:end_time;type:time;comment:结束时间" json:"end_time"`
}
type Schedule struct {
ID int `gorm:"primaryKey;autoIncrement" json:"id"`
EventID int `gorm:"column:event_id;index:idx_event_id;not null;comment:关联元数据ID" json:"event_id"`
UserID int `gorm:"column:user_id;uniqueIndex:idx_user_slot_atomic,priority:1;not null;comment:冗余UID方便直接查询" json:"user_id"`
Week int `gorm:"column:week;uniqueIndex:idx_user_slot_atomic,priority:2;not null;comment:周次 (1-25)" json:"week"`
DayOfWeek int `gorm:"column:day_of_week;uniqueIndex:idx_user_slot_atomic,priority:3;not null;comment:星期 (1-7)" json:"day_of_week"`
Section int `gorm:"column:section;uniqueIndex:idx_user_slot_atomic,priority:4;not null;comment:原子化节次 (1-12)" json:"section"`
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"`
EmbeddedTask *TaskClassItem `gorm:"foreignKey:EmbeddedTaskID" json:"embedded_task"`
}
type ScheduleConflictDetail struct {
EventID int `json:"event_id"`
Name string `json:"name"`
Location string `json:"location"`
DayOfWeek int `json:"day_of_week"`
Week int `json:"week"`
Sections []int `json:"sections"`
StartSection int `json:"start_section"`
EndSection int `json:"end_section"`
Type string `json:"type"`
EmbeddedTasks []ScheduleEmbeddedTask `json:"embedded_tasks"`
}
type ScheduleEmbeddedTask struct {
Section int `json:"section"`
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"`
}
type UserWeekSchedule struct {
Week int `json:"week"`
Events []WeeklyEventBrief `json:"events"`
}
type WeeklyEventBrief struct {
ID int `json:"id"` // 这个 ID 是 ScheduleEvent 的 ID不是 Schedule 的 ID
Order int `json:"order"` // order 用于区分它们在一天中的显示顺序
DayOfWeek int `json:"day_of_week"`
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"` // 跨越的节数,给前端用来渲染宽度/高度
Status string `json:"status"`
EmbeddedTaskInfo TaskBrief `json:"embedded_task_info,omitempty"`
}
type UserDeleteScheduleEvent struct {
ID int `json:"id"` // 这个 ID 是 ScheduleEvent 的 ID不是 Schedule 的 ID
DeleteCourse bool `json:"delete_course"`
DeleteEmbeddedTask bool `json:"delete_embedded_task"`
}
// UserSmartPlanningMultiRequest 是“多任务类智能粗排”接口的请求体。
//
// 设计说明:
// 1. TaskClassIDs 至少包含 1 个任务类 ID
// 2. 实际业务建议传入 >=2 个,用于多任务类混排;
// 3. 服务层会做去重与合法值过滤,接口层只做基础绑定校验。
type UserSmartPlanningMultiRequest struct {
TaskClassIDs []int `json:"task_class_ids" binding:"required,min=1,dive,min=1"`
}
type UserRecentCompletedScheduleResponse struct {
Events []RecentCompletedEventBrief `json:"events"`
}
type RecentCompletedEventBrief struct {
ID int `json:"id"` //如果是嵌入的任务事件这个ID是TaskClassItem的ID如果是课程事件这个ID是ScheduleEvent的ID
Name string `json:"name"`
Type string `json:"type"`
CompletedTime string `json:"completed_time"`
}
type OngoingSchedule struct {
ID int `json:"id"` // 这个 ID 是 ScheduleEvent 的 ID不是 Schedule 的 ID
Name string `json:"name"`
Location string `json:"location"`
Type string `json:"type"`
TimeStatus string `json:"time_status"` // "upcoming", "ongoing"
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
}
// HybridScheduleEntry 表示"混合日程"中的一个时间块。
//
// 设计目标:
// 将既有日程(课程/已落库任务)与粗排建议的任务统一到同一结构中,
// 供 ReAct 精排引擎在内存中操作。
//
// Status 语义:
// - "existing"已确定的日程LLM 不可移动;
// - "suggested"粗排建议的任务LLM 可通过 Tool 调整时间。
type HybridScheduleEntry struct {
Week int `json:"week"`
DayOfWeek int `json:"day_of_week"`
SectionFrom int `json:"section_from"`
SectionTo int `json:"section_to"`
Name string `json:"name"`
Type string `json:"type"` // "course" | "task"
Status string `json:"status"` // "existing" | "suggested"
TaskItemID int `json:"task_item_id,omitempty"` // 仅 suggested 的 task 有值
TaskClassID int `json:"task_class_id,omitempty"` // 仅 suggested 的 task 有值,对应 TaskClass.ID
EventID int `json:"event_id,omitempty"` // 仅 existing 有值
// CanBeEmbedded 表示该条 existing 课程块是否允许嵌入任务。
// 仅课程条目有意义task 条目默认 false。
CanBeEmbedded bool `json:"can_be_embedded,omitempty"`
// BlockForSuggested 表示该条目是否应当阻塞 suggested 任务占位。
//
// 语义说明:
// 1. suggested 条目默认 true任务之间不能重叠
// 2. existing 课程若是“可嵌入且当前格子未被嵌入任务占用”,则为 false
// 3. existing 课程若不可嵌入,或该格子已有嵌入任务,则为 true。
//
// 该字段用于工具层冲突判断,避免把“可嵌入课位”误判为硬冲突。
BlockForSuggested bool `json:"block_for_suggested,omitempty"`
// ContextTag 是任务认知类型标签,仅在 suggested 任务中使用。
// 该标签用于日内优化时的“认知负荷分配”,例如:
// 1. High-Logic数学、编程、逻辑推理
// 2. Memory记忆/背诵类;
// 3. Review复习/回顾类;
// 4. General通用任务。
ContextTag string `json:"context_tag,omitempty"`
}
func (ScheduleEvent) TableName() string { return "schedule_events" }
func (Schedule) TableName() string { return "schedules" }