Version: 0.9.59.dev.260430
后端: 1. 主动调度预览确认主链路落地——新增主动调度数据模型、DAO 与事件契约;接入 dry-run pipeline 与任务触发的 job upsert/cancel;新增 preview 查询与 confirm API,支持 apply_id 幂等确认并同步写入 task_pool 日程 2. 同步更新主动调度实施文档的阶段状态与验收记录 前端: 3. AssistantPanel 脚本层继续解耦——私有类型迁移到独立类型文件,并抽离会话、工具轨迹、思考摘要、任务表单等纯函数辅助逻辑;保持助手面板模板与样式不变,降低表现层回归风险
This commit is contained in:
264
backend/model/active_schedule.go
Normal file
264
backend/model/active_schedule.go
Normal file
@@ -0,0 +1,264 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveScheduleJobStatusPending 表示 job 已创建,等待到达 trigger_at 后扫描。
|
||||
ActiveScheduleJobStatusPending = "pending"
|
||||
// ActiveScheduleJobStatusTriggered 表示 job 已生成正式 trigger,后续由 trigger 串联状态。
|
||||
ActiveScheduleJobStatusTriggered = "triggered"
|
||||
// ActiveScheduleJobStatusCanceled 表示任务已完成或被取消,job 不再触发。
|
||||
ActiveScheduleJobStatusCanceled = "canceled"
|
||||
// ActiveScheduleJobStatusSkipped 表示扫描时发现已无需主动调度。
|
||||
ActiveScheduleJobStatusSkipped = "skipped"
|
||||
// ActiveScheduleJobStatusFailed 表示扫描或触发写入失败,保留错误供重试/排障。
|
||||
ActiveScheduleJobStatusFailed = "failed"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveScheduleTriggerStatusPending 表示触发信号已持久化,等待 worker 消费。
|
||||
ActiveScheduleTriggerStatusPending = "pending"
|
||||
// ActiveScheduleTriggerStatusProcessing 表示 worker 正在处理该触发信号。
|
||||
ActiveScheduleTriggerStatusProcessing = "processing"
|
||||
// ActiveScheduleTriggerStatusPreviewGenerated 表示已生成可查询的预览。
|
||||
ActiveScheduleTriggerStatusPreviewGenerated = "preview_generated"
|
||||
// ActiveScheduleTriggerStatusSkipped 表示本次触发被判定无需继续处理。
|
||||
ActiveScheduleTriggerStatusSkipped = "skipped"
|
||||
// ActiveScheduleTriggerStatusClosed 表示主动观测结论为关闭,不生成预览。
|
||||
ActiveScheduleTriggerStatusClosed = "closed"
|
||||
// ActiveScheduleTriggerStatusFailed 表示链路处理失败,可根据错误分类决定是否重试。
|
||||
ActiveScheduleTriggerStatusFailed = "failed"
|
||||
// ActiveScheduleTriggerStatusRejected 表示参数或归属校验失败,不进入 pipeline。
|
||||
ActiveScheduleTriggerStatusRejected = "rejected"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveSchedulePreviewStatusPending 表示预览正在组装,不应展示为可确认。
|
||||
ActiveSchedulePreviewStatusPending = "pending"
|
||||
// ActiveSchedulePreviewStatusReady 表示预览可查看、可确认。
|
||||
ActiveSchedulePreviewStatusReady = "ready"
|
||||
// ActiveSchedulePreviewStatusApplied 表示用户已确认并成功应用。
|
||||
ActiveSchedulePreviewStatusApplied = "applied"
|
||||
// ActiveSchedulePreviewStatusIgnored 表示用户明确忽略本次建议。
|
||||
ActiveSchedulePreviewStatusIgnored = "ignored"
|
||||
// ActiveSchedulePreviewStatusExpired 表示预览已过期,不再允许确认。
|
||||
ActiveSchedulePreviewStatusExpired = "expired"
|
||||
// ActiveSchedulePreviewStatusFailed 表示预览生成或回写失败。
|
||||
ActiveSchedulePreviewStatusFailed = "failed"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveScheduleApplyStatusNone 表示尚未发起确认应用。
|
||||
ActiveScheduleApplyStatusNone = "none"
|
||||
// ActiveScheduleApplyStatusApplying 表示确认请求正在事务应用中。
|
||||
ActiveScheduleApplyStatusApplying = "applying"
|
||||
// ActiveScheduleApplyStatusApplied 表示确认应用成功。
|
||||
ActiveScheduleApplyStatusApplied = "applied"
|
||||
// ActiveScheduleApplyStatusFailed 表示应用失败,正式日程不应产生半写状态。
|
||||
ActiveScheduleApplyStatusFailed = "failed"
|
||||
// ActiveScheduleApplyStatusRejected 表示请求因过期、幂等冲突等业务规则被拒绝。
|
||||
ActiveScheduleApplyStatusRejected = "rejected"
|
||||
// ActiveScheduleApplyStatusExpired 表示预览过期导致不可应用。
|
||||
ActiveScheduleApplyStatusExpired = "expired"
|
||||
)
|
||||
|
||||
const (
|
||||
// NotificationRecordStatusPending 表示通知记录已落库,等待投递。
|
||||
NotificationRecordStatusPending = "pending"
|
||||
// NotificationRecordStatusSending 表示当前 worker 正在调用 provider。
|
||||
NotificationRecordStatusSending = "sending"
|
||||
// NotificationRecordStatusSent 表示 provider 明确返回成功。
|
||||
NotificationRecordStatusSent = "sent"
|
||||
// NotificationRecordStatusFailed 表示本次投递失败,但仍可重试。
|
||||
NotificationRecordStatusFailed = "failed"
|
||||
// NotificationRecordStatusDead 表示达到重试上限或不可恢复错误。
|
||||
NotificationRecordStatusDead = "dead"
|
||||
// NotificationRecordStatusSkipped 表示命中去重或配置关闭,本次不投递。
|
||||
NotificationRecordStatusSkipped = "skipped"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveScheduleTriggerTypeImportantUrgentTask 是重要且紧急任务到线触发。
|
||||
ActiveScheduleTriggerTypeImportantUrgentTask = "important_urgent_task"
|
||||
// ActiveScheduleTriggerTypeUnfinishedFeedback 是用户明确反馈已排任务未完成触发。
|
||||
ActiveScheduleTriggerTypeUnfinishedFeedback = "unfinished_feedback"
|
||||
|
||||
// ActiveScheduleSourceWorkerDueJob 表示后台到期 job 扫描触发。
|
||||
ActiveScheduleSourceWorkerDueJob = "worker_due_job"
|
||||
// ActiveScheduleSourceAPITrigger 表示测试/开发 API 正式触发。
|
||||
ActiveScheduleSourceAPITrigger = "api_trigger"
|
||||
// ActiveScheduleSourceAPIDryRun 表示测试/开发 API dry-run,不应发布正式事件。
|
||||
ActiveScheduleSourceAPIDryRun = "api_dry_run"
|
||||
// ActiveScheduleSourceUserFeedback 表示用户反馈入口触发。
|
||||
ActiveScheduleSourceUserFeedback = "user_feedback"
|
||||
|
||||
// ActiveScheduleTargetTypeTaskPool 表示 target_id 指向 tasks.id。
|
||||
ActiveScheduleTargetTypeTaskPool = "task_pool"
|
||||
// ActiveScheduleTargetTypeScheduleEvent 表示 target_id 指向 schedule_events.id。
|
||||
ActiveScheduleTargetTypeScheduleEvent = "schedule_event"
|
||||
// ActiveScheduleTargetTypeTaskItem 表示 target_id 指向 task_items.id。
|
||||
ActiveScheduleTargetTypeTaskItem = "task_item"
|
||||
)
|
||||
|
||||
// ActiveScheduleJob 是主动调度 due job 表模型。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责记录 task 到达 urgency_threshold_at 后是否需要生成主动调度触发;
|
||||
// 2. 不负责判断 task 当前是否仍重要且紧急,该判断由 worker 扫描时重新读取真实任务状态;
|
||||
// 3. 不负责发布 outbox 事件,只保存扫描和排障所需状态。
|
||||
type ActiveScheduleJob struct {
|
||||
ID string `gorm:"column:id;type:varchar(64);primaryKey"`
|
||||
|
||||
UserID int `gorm:"column:user_id;not null;index:idx_active_jobs_user_status_trigger,priority:1;index:idx_active_jobs_task_status,priority:1"`
|
||||
TaskID int `gorm:"column:task_id;not null;index:idx_active_jobs_task_status,priority:2;comment:对应 tasks.id"`
|
||||
TriggerType string `gorm:"column:trigger_type;type:varchar(64);not null;default:'important_urgent_task';comment:触发类型"`
|
||||
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_active_jobs_user_status_trigger,priority:2;index:idx_active_jobs_task_status,priority:3;comment:pending/triggered/canceled/skipped/failed"`
|
||||
TriggerAt time.Time `gorm:"column:trigger_at;not null;index:idx_active_jobs_user_status_trigger,priority:3;comment:到期触发时间"`
|
||||
|
||||
DedupeKey string `gorm:"column:dedupe_key;type:varchar(191);index:idx_active_jobs_dedupe;comment:触发去重窗口键"`
|
||||
LastTriggerID *string `gorm:"column:last_trigger_id;type:varchar(64);index:idx_active_jobs_last_trigger;comment:最近一次生成的 trigger_id"`
|
||||
LastErrorCode *string `gorm:"column:last_error_code;type:varchar(64);comment:最近一次扫描错误码"`
|
||||
LastError *string `gorm:"column:last_error;type:text;comment:最近一次扫描错误详情"`
|
||||
LastScannedAt *time.Time `gorm:"column:last_scanned_at;comment:最近一次被 worker 扫描时间"`
|
||||
TraceID string `gorm:"column:trace_id;type:varchar(64);index:idx_active_jobs_trace_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
|
||||
}
|
||||
|
||||
func (ActiveScheduleJob) TableName() string { return "active_schedule_jobs" }
|
||||
|
||||
// ActiveScheduleTrigger 是主动调度统一触发信号表模型。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责持久化 worker/API/用户反馈归一后的触发事实;
|
||||
// 2. 负责串联 trigger -> preview -> notification -> apply 的审计主线;
|
||||
// 3. 不承载候选生成、LLM 选择或通知投递的业务实现。
|
||||
type ActiveScheduleTrigger struct {
|
||||
ID string `gorm:"column:id;type:varchar(64);primaryKey"`
|
||||
|
||||
UserID int `gorm:"column:user_id;not null;index:idx_active_triggers_user_created,priority:1"`
|
||||
TriggerType string `gorm:"column:trigger_type;type:varchar(64);not null;index:idx_active_triggers_dedupe,priority:2"`
|
||||
Source string `gorm:"column:source;type:varchar(64);not null;comment:worker_due_job/api_trigger/api_dry_run/user_feedback"`
|
||||
TargetType string `gorm:"column:target_type;type:varchar(64);not null;index:idx_active_triggers_target,priority:1"`
|
||||
TargetID int `gorm:"column:target_id;not null;index:idx_active_triggers_target,priority:2"`
|
||||
FeedbackID string `gorm:"column:feedback_id;type:varchar(128);index:idx_active_triggers_feedback;comment:用户反馈来源ID,可为空"`
|
||||
JobID *string `gorm:"column:job_id;type:varchar(64);index:idx_active_triggers_job_id"`
|
||||
IdempotencyKey string `gorm:"column:idempotency_key;type:varchar(191);index:idx_active_triggers_idempotency;comment:API/用户反馈幂等键"`
|
||||
DedupeKey string `gorm:"column:dedupe_key;type:varchar(191);index:idx_active_triggers_dedupe,priority:1;comment:触发去重窗口键"`
|
||||
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_active_triggers_status_updated,priority:1"`
|
||||
MockNow *time.Time `gorm:"column:mock_now;comment:测试触发模拟时间"`
|
||||
IsMockTime bool `gorm:"column:is_mock_time;not null;default:false;comment:是否使用模拟时间"`
|
||||
RequestedAt time.Time `gorm:"column:requested_at;not null;comment:触发请求时间"`
|
||||
PayloadJSON *string `gorm:"column:payload_json;type:json;comment:触发来源补充信息"`
|
||||
PreviewID *string `gorm:"column:preview_id;type:varchar(64);index:idx_active_triggers_preview_id"`
|
||||
LastErrorCode *string `gorm:"column:last_error_code;type:varchar(64);comment:链路错误码"`
|
||||
LastError *string `gorm:"column:last_error;type:text;comment:链路错误详情"`
|
||||
ProcessedAt *time.Time `gorm:"column:processed_at;comment:worker 开始处理时间"`
|
||||
CompletedAt *time.Time `gorm:"column:completed_at;comment:本触发进入终态时间"`
|
||||
TraceID string `gorm:"column:trace_id;type:varchar(64);index:idx_active_triggers_trace_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_active_triggers_user_created,priority:2"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;index:idx_active_triggers_status_updated,priority:2"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
|
||||
}
|
||||
|
||||
func (ActiveScheduleTrigger) TableName() string { return "active_schedule_triggers" }
|
||||
|
||||
// ActiveSchedulePreview 是主动调度可确认预览表模型。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责保存主动调度生成的候选、解释、before/after 摘要与过期时间;
|
||||
// 2. 负责保存一次确认应用的轻量状态,不新增 apply request 表;
|
||||
// 3. 不负责正式日程写入,正式写入仍由后续 apply/service port 完成。
|
||||
type ActiveSchedulePreview struct {
|
||||
ID string `gorm:"column:preview_id;type:varchar(64);primaryKey;uniqueIndex:uk_active_previews_apply_idempotency,priority:1"`
|
||||
|
||||
UserID int `gorm:"column:user_id;not null;index:idx_active_previews_user_created_at,priority:1"`
|
||||
TriggerID string `gorm:"column:trigger_id;type:varchar(64);not null;index:idx_active_previews_trigger_id"`
|
||||
TriggerType string `gorm:"column:trigger_type;type:varchar(64);not null"`
|
||||
TargetType string `gorm:"column:target_type;type:varchar(64);not null"`
|
||||
TargetID int `gorm:"column:target_id;not null"`
|
||||
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';comment:pending/ready/applied/ignored/expired/failed"`
|
||||
|
||||
SelectedCandidateID string `gorm:"column:selected_candidate_id;type:varchar(64);comment:LLM 或后端 fallback 选中的候选ID"`
|
||||
CandidateCount int `gorm:"column:candidate_count;not null;default:0"`
|
||||
SelectedCandidateJSON *string `gorm:"column:selected_candidate_json;type:json"`
|
||||
CandidatesJSON *string `gorm:"column:candidates_json;type:json"`
|
||||
DecisionJSON *string `gorm:"column:decision_json;type:json"`
|
||||
MetricsJSON *string `gorm:"column:metrics_json;type:json"`
|
||||
IssuesJSON *string `gorm:"column:issues_json;type:json"`
|
||||
ContextSummaryJSON *string `gorm:"column:context_summary_json;type:json"`
|
||||
BeforeSummaryJSON *string `gorm:"column:before_summary_json;type:json"`
|
||||
PreviewChangesJSON *string `gorm:"column:preview_changes_json;type:json"`
|
||||
AfterSummaryJSON *string `gorm:"column:after_summary_json;type:json"`
|
||||
RiskJSON *string `gorm:"column:risk_json;type:json"`
|
||||
ExplanationText string `gorm:"column:explanation_text;type:text"`
|
||||
NotificationSummary string `gorm:"column:notification_summary;type:text"`
|
||||
BaseVersion string `gorm:"column:base_version;type:varchar(128);not null;comment:确认前重校验基准版本"`
|
||||
ExpiresAt time.Time `gorm:"column:expires_at;not null;index:idx_active_previews_expires_at"`
|
||||
GeneratedAt time.Time `gorm:"column:generated_at;not null"`
|
||||
|
||||
ApplyID *string `gorm:"column:apply_id;type:varchar(64);index:idx_active_previews_apply_id"`
|
||||
ApplyStatus string `gorm:"column:apply_status;type:varchar(32);not null;default:'none';comment:none/applying/applied/failed/rejected/expired"`
|
||||
ApplyCandidateID string `gorm:"column:apply_candidate_id;type:varchar(64)"`
|
||||
ApplyIdempotencyKey string `gorm:"column:apply_idempotency_key;type:varchar(191);uniqueIndex:uk_active_previews_apply_idempotency,priority:2"`
|
||||
ApplyRequestHash string `gorm:"column:apply_request_hash;type:varchar(128);comment:确认请求体摘要"`
|
||||
AppliedChangesJSON *string `gorm:"column:applied_changes_json;type:json"`
|
||||
AppliedEventIDsJSON *string `gorm:"column:applied_event_ids_json;type:json"`
|
||||
ApplyError *string `gorm:"column:apply_error;type:text"`
|
||||
AppliedAt *time.Time `gorm:"column:applied_at"`
|
||||
TraceID string `gorm:"column:trace_id;type:varchar(64);index:idx_active_previews_trace_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_active_previews_user_created_at,priority:2"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
|
||||
}
|
||||
|
||||
func (ActiveSchedulePreview) TableName() string { return "active_schedule_previews" }
|
||||
|
||||
// NotificationRecord 是通知投递记录表模型。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责记录飞书等通知渠道的幂等、状态流转和 provider 返回;
|
||||
// 2. 不负责决定是否生成调度预览,也不负责 apply 状态;
|
||||
// 3. 重试时复用同一条记录,避免短时间重复打扰用户。
|
||||
type NotificationRecord struct {
|
||||
ID int64 `gorm:"column:id;primaryKey;autoIncrement"`
|
||||
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null;uniqueIndex:uk_notification_dedupe,priority:1;comment:通知渠道"`
|
||||
UserID int `gorm:"column:user_id;not null;index:idx_notification_user_created,priority:1"`
|
||||
TriggerID string `gorm:"column:trigger_id;type:varchar(64);not null;index:idx_notification_trigger"`
|
||||
PreviewID string `gorm:"column:preview_id;type:varchar(64);not null;index:idx_notification_preview"`
|
||||
TriggerType string `gorm:"column:trigger_type;type:varchar(64);not null"`
|
||||
TargetType string `gorm:"column:target_type;type:varchar(64);not null"`
|
||||
TargetID int `gorm:"column:target_id;not null"`
|
||||
DedupeKey string `gorm:"column:dedupe_key;type:varchar(191);not null;uniqueIndex:uk_notification_dedupe,priority:2"`
|
||||
TargetURL string `gorm:"column:target_url;type:varchar(255);not null;comment:站内预览链接"`
|
||||
SummaryText string `gorm:"column:summary_text;type:text"`
|
||||
FallbackText string `gorm:"column:fallback_text;type:text"`
|
||||
FallbackUsed bool `gorm:"column:fallback_used;not null;default:false"`
|
||||
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_notification_status_retry,priority:1;comment:pending/sending/sent/failed/dead/skipped"`
|
||||
AttemptCount int `gorm:"column:attempt_count;not null;default:0"`
|
||||
MaxAttempts int `gorm:"column:max_attempts;not null;default:5"`
|
||||
NextRetryAt *time.Time `gorm:"column:next_retry_at;index:idx_notification_status_retry,priority:2"`
|
||||
LastErrorCode *string `gorm:"column:last_error_code;type:varchar(64)"`
|
||||
LastError *string `gorm:"column:last_error;type:text"`
|
||||
|
||||
ProviderMessageID *string `gorm:"column:provider_message_id;type:varchar(128)"`
|
||||
ProviderRequestJSON *string `gorm:"column:provider_request_json;type:json"`
|
||||
ProviderResponseJSON *string `gorm:"column:provider_response_json;type:json"`
|
||||
SentAt *time.Time `gorm:"column:sent_at"`
|
||||
TraceID string `gorm:"column:trace_id;type:varchar(64);index:idx_notification_trace_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_notification_user_created,priority:2"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
|
||||
}
|
||||
|
||||
func (NotificationRecord) TableName() string { return "notification_records" }
|
||||
@@ -3,15 +3,35 @@ 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"`
|
||||
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"`
|
||||
// TaskSourceType 标记 type=task 时 rel_id 指向哪个任务来源。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 只表达任务日程块的数据来源,不改变 Type 的 course/task 展示语义;
|
||||
// 2. task_item 表示 rel_id 指向 task_items.id,task_pool 表示 rel_id 指向 tasks.id;
|
||||
// 3. 课程事件保持空值,由迁移回填历史 task 事件,避免影响现有课程逻辑。
|
||||
TaskSourceType string `gorm:"column:task_source_type;type:varchar(32);not null;default:'';index:idx_schedule_event_task_source;comment:任务来源 task_item/task_pool" json:"task_source_type,omitempty"`
|
||||
// MakeupForEventID 记录补做块来源事件,用于用户反馈未完成后的审计串联。
|
||||
//
|
||||
// 说明:
|
||||
// 1. 只有主动调度生成补做块时写入;
|
||||
// 2. 不负责校验目标事件是否仍存在,正式 apply 链路需要在事务内重校验;
|
||||
// 3. 为空表示普通日程块或非补做块。
|
||||
MakeupForEventID *int `gorm:"column:makeup_for_event_id;index:idx_schedule_event_makeup_for;comment:补做块对应的原 schedule_event.id" json:"makeup_for_event_id,omitempty"`
|
||||
// ActivePreviewID 记录主动调度预览来源,方便从正式日程反查触发链路。
|
||||
//
|
||||
// 说明:
|
||||
// 1. 该字段只做审计与排障,不作为正式日程主键;
|
||||
// 2. preview 详情仍归 active_schedule_previews 表所有。
|
||||
ActivePreviewID *string `gorm:"column:active_preview_id;type:varchar(64);index:idx_schedule_event_active_preview;comment:主动调度预览ID" json:"active_preview_id,omitempty"`
|
||||
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 {
|
||||
|
||||
@@ -39,6 +39,13 @@ type Task struct {
|
||||
// 7.3 为空表示该任务不参与自动平移;
|
||||
// 7.4 该字段参与"懒触发平移"复合索引。
|
||||
UrgencyThresholdAt *time.Time `gorm:"column:urgency_threshold_at;index:idx_user_done_threshold_priority,priority:3"`
|
||||
// 8. 任务预计占用节数。
|
||||
//
|
||||
// 说明:
|
||||
// 8.1 主动调度只消费该字段,不在调度阶段重新推断任务复杂度;
|
||||
// 8.2 MVP 约定有效范围为 1~4,模型层仅提供默认值,具体截断由主动调度上下文构造负责;
|
||||
// 8.3 默认 1 节,兼容历史任务与未显式填写的任务。
|
||||
EstimatedSections int `gorm:"column:estimated_sections;not null;default:1"`
|
||||
}
|
||||
|
||||
type UserAddTaskResponse struct {
|
||||
|
||||
Reference in New Issue
Block a user