package model import "time" // DetectionTask 统一检测任务,覆盖 LAMP/qPCR/SERS/高光谱。 type DetectionTask struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` SourceKey string `gorm:"column:source_key;size:128;uniqueIndex" json:"sourceKey,omitempty"` SourceType string `gorm:"column:source_type;size:32" json:"sourceType"` SourceID string `gorm:"column:source_id;size:128" json:"sourceId,omitempty"` RoomID *string `gorm:"column:room_id;type:uuid;index" json:"roomId,omitempty"` BatchID *string `gorm:"column:batch_id;type:uuid;index" json:"batchId,omitempty"` InspectionID *string `gorm:"column:inspection_id;type:uuid;index" json:"inspectionId,omitempty"` Disease string `gorm:"size:64" json:"disease"` RecommendedMethod string `gorm:"column:recommended_method;size:32" json:"recommendedMethod,omitempty"` Method *string `gorm:"size:32" json:"method,omitempty"` Priority string `gorm:"size:16;default:routine" json:"priority"` Status string `gorm:"size:16;default:pending;index" json:"status"` AssigneeID *string `gorm:"column:assignee_id;type:uuid" json:"assigneeId,omitempty"` AssignedAt *time.Time `gorm:"column:assigned_at;type:timestamptz" json:"assignedAt,omitempty"` Result *string `gorm:"size:16" json:"result,omitempty"` ResultedAt *time.Time `gorm:"column:resulted_at;type:timestamptz" json:"resultedAt,omitempty"` CancelledReason *string `gorm:"column:cancelled_reason;type:text" json:"cancelledReason,omitempty"` CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"` Note *string `gorm:"type:text" json:"note,omitempty"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` RoomName *string `gorm:"-" json:"roomName,omitempty"` } func (DetectionTask) TableName() string { return "detection_tasks" } // ValidDetectionTaskTransition 状态机:draft/pending/assigned/sampling/testing/review/completed/cancelled。 func ValidDetectionTaskTransition(from, to string) bool { switch from { case "draft": return to == "pending" || to == "cancelled" case "pending": return to == "assigned" || to == "cancelled" case "assigned": return to == "sampling" || to == "cancelled" case "sampling": return to == "testing" || to == "cancelled" case "testing": return to == "review" || to == "cancelled" case "review": return to == "completed" || to == "cancelled" default: return false } } // Sample 检测样本链路。 type Sample struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` DetectionTaskID string `gorm:"column:detection_task_id;type:uuid;uniqueIndex" json:"detectionTaskId"` SampleNo string `gorm:"column:sample_no;size:64;uniqueIndex" json:"sampleNo"` RoomID *string `gorm:"column:room_id;type:uuid;index" json:"roomId,omitempty"` BatchID *string `gorm:"column:batch_id;type:uuid;index" json:"batchId,omitempty"` TrayID *string `gorm:"column:tray_id;type:uuid" json:"trayId,omitempty"` SampledBy *string `gorm:"column:sampled_by;type:uuid" json:"sampledBy,omitempty"` SampledAt *time.Time `gorm:"column:sampled_at;type:timestamptz" json:"sampledAt,omitempty"` CollectedAt *time.Time `gorm:"column:collected_at;type:timestamptz" json:"collectedAt,omitempty"` HandedOverAt *time.Time `gorm:"column:handed_over_at;type:timestamptz" json:"handedOverAt,omitempty"` HandedOverBy *string `gorm:"column:handed_over_by;type:uuid" json:"handedOverBy,omitempty"` ReceivedAt *time.Time `gorm:"column:received_at;type:timestamptz" json:"receivedAt,omitempty"` ReceivedBy *string `gorm:"column:received_by;type:uuid" json:"receivedBy,omitempty"` TestingStartedAt *time.Time `gorm:"column:testing_started_at;type:timestamptz" json:"testingStartedAt,omitempty"` ConsumedAt *time.Time `gorm:"column:consumed_at;type:timestamptz" json:"consumedAt,omitempty"` DisposedAt *time.Time `gorm:"column:disposed_at;type:timestamptz" json:"disposedAt,omitempty"` State string `gorm:"size:16;default:created" json:"state"` Note *string `gorm:"type:text" json:"note,omitempty"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (Sample) TableName() string { return "samples" } // ValidSampleTransition 样本状态机:created/collected/handed_over/received/testing/consumed/disposed。 func ValidSampleTransition(from, to string) bool { switch from { case "created": return to == "collected" || to == "disposed" case "collected": return to == "handed_over" || to == "disposed" case "handed_over": return to == "received" || to == "disposed" case "received": return to == "testing" || to == "disposed" case "testing": return to == "consumed" || to == "disposed" case "consumed": return to == "disposed" default: return false } }