Files
silk/server-go/internal/model/business_capabilities.go
2026-08-17 21:43:26 +08:00

217 lines
11 KiB
Go

package model
import (
"encoding/json"
"errors"
"strings"
"time"
)
// Organization 组织/养殖场/合作社,用于对象级数据授权。
type Organization struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
Name string `gorm:"size:128" json:"name"`
Code string `gorm:"size:64;uniqueIndex" json:"code"`
Description *string `gorm:"type:text" json:"description,omitempty"`
Status string `gorm:"size:16;default:active" json:"status"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
}
func (Organization) TableName() string { return "organizations" }
// OrganizationMember 用户与组织归属关系。
type OrganizationMember struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
OrganizationID string `gorm:"column:organization_id;type:uuid;uniqueIndex:idx_org_members_org_user,priority:1" json:"organizationId"`
UserID string `gorm:"column:user_id;type:uuid;uniqueIndex:idx_org_members_org_user,priority:2" json:"userId"`
Role string `gorm:"size:16;default:member" json:"role"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
}
func (OrganizationMember) TableName() string { return "organization_members" }
// DeviceMaintenanceRecord 设备校准/故障/维护/固件记录。
type DeviceMaintenanceRecord struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
DeviceID string `gorm:"column:device_id;type:uuid;index" json:"deviceId"`
Kind string `gorm:"size:16;index" json:"kind"` // calibration/fault/maintenance/firmware
Title string `gorm:"size:128" json:"title"`
ScheduledAt *time.Time `gorm:"column:scheduled_at;type:timestamptz" json:"scheduledAt,omitempty"`
PerformedAt *time.Time `gorm:"column:performed_at;type:timestamptz" json:"performedAt,omitempty"`
PerformerID *string `gorm:"column:performer_id;type:uuid" json:"performerId,omitempty"`
Result *string `gorm:"type:text" json:"result,omitempty"`
FirmwareFrom *string `gorm:"column:firmware_from;size:64" json:"firmwareFrom,omitempty"`
FirmwareTo *string `gorm:"column:firmware_to;size:64" json:"firmwareTo,omitempty"`
CostAmount *float64 `gorm:"column:cost_amount;type:float" json:"costAmount,omitempty"`
CostUnit *string `gorm:"column:cost_unit;size:16" json:"costUnit,omitempty"`
Note *string `gorm:"type:text" json:"note,omitempty"`
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
}
func (DeviceMaintenanceRecord) TableName() string { return "device_maintenance_records" }
// ValidMaintenanceKind 设备维护记录类型。
func ValidMaintenanceKind(kind string) bool {
switch kind {
case "calibration", "fault", "maintenance", "firmware":
return true
default:
return false
}
}
// ValidateDeviceMaintenanceRecord 设备维护必填项。
func ValidateDeviceMaintenanceRecord(record DeviceMaintenanceRecord) error {
if !ValidMaintenanceKind(record.Kind) {
return errors.New("kind 仅支持 calibration/fault/maintenance/firmware")
}
if strings.TrimSpace(record.Title) == "" {
return errors.New("维护标题不能为空")
}
return nil
}
// ProductionLossRecord 产量、死亡、淘汰、损失和防控成本记录。
type ProductionLossRecord struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
RoomID *string `gorm:"column:room_id;type:uuid;index" json:"roomId,omitempty"`
BatchID *string `gorm:"column:batch_id;type:uuid;index" json:"batchId,omitempty"`
RecordDate time.Time `gorm:"column:record_date;type:timestamptz;index" json:"recordDate"`
DeathCount *int `gorm:"column:death_count;type:int" json:"deathCount,omitempty"`
CulledCount *int `gorm:"column:culled_count;type:int" json:"culledCount,omitempty"`
YieldKg *float64 `gorm:"column:yield_kg;type:float" json:"yieldKg,omitempty"`
LossKg *float64 `gorm:"column:loss_kg;type:float" json:"lossKg,omitempty"`
CostType *string `gorm:"column:cost_type;size:32" json:"costType,omitempty"` // medicine/disinfection/detection/labor/other
CostAmount *float64 `gorm:"column:cost_amount;type:float" json:"costAmount,omitempty"`
Note *string `gorm:"type:text" json:"note,omitempty"`
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
}
func (ProductionLossRecord) TableName() string { return "production_loss_records" }
// ValidateProductionLossRecord 产量损失记录必须至少有一个业务数值。
func ValidateProductionLossRecord(record ProductionLossRecord) error {
if record.RoomID == nil && record.BatchID == nil {
return errors.New("roomId/batchId 至少填一个")
}
if record.RecordDate.IsZero() {
return errors.New("记录日期不能为空")
}
hasValue := record.DeathCount != nil || record.CulledCount != nil ||
record.YieldKg != nil || record.LossKg != nil || record.CostAmount != nil
if !hasValue {
return errors.New("死亡/淘汰/产量/损失/成本至少填写一项")
}
return nil
}
// CaseStudy 已脱敏病例沉淀,必须经审核后发布。
type CaseStudy struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
Title string `gorm:"size:128" json:"title"`
Disease string `gorm:"size:64;index" json:"disease"`
SourceConsultationID *string `gorm:"column:source_consultation_id;type:uuid;index" json:"sourceConsultationId,omitempty"`
SourceDiseaseEventID *string `gorm:"column:source_disease_event_id;type:uuid;index" json:"sourceDiseaseEventId,omitempty"`
SourceRoomID *string `gorm:"column:source_room_id;type:uuid;index" json:"sourceRoomId,omitempty"`
Region *string `gorm:"size:64" json:"region,omitempty"`
CaseDate *time.Time `gorm:"column:case_date;type:timestamptz" json:"caseDate,omitempty"`
Summary *string `gorm:"type:text" json:"summary,omitempty"`
DesensitizedPayload json.RawMessage `gorm:"column:desensitized_payload;type:jsonb" json:"desensitizedPayload,omitempty"`
Status string `gorm:"size:16;default:draft;index" json:"status"` // draft/pending_review/published/rejected
ReviewNote *string `gorm:"column:review_note;type:text" json:"reviewNote,omitempty"`
ReviewerID *string `gorm:"column:reviewer_id;type:uuid" json:"reviewerId,omitempty"`
ReviewedAt *time.Time `gorm:"column:reviewed_at;type:timestamptz" json:"reviewedAt,omitempty"`
PublishedAt *time.Time `gorm:"column:published_at;type:timestamptz" json:"publishedAt,omitempty"`
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
}
func (CaseStudy) TableName() string { return "case_studies" }
// ValidCaseStudyTransition 案例审核状态流转。
func ValidCaseStudyTransition(from, to string) bool {
switch from {
case "draft":
return to == "pending_review" || to == "rejected"
case "pending_review":
return to == "published" || to == "rejected"
case "published":
return to == "rejected" || to == "pending_review"
case "rejected":
return to == "draft" || to == "pending_review"
default:
return false
}
}
// LaboratoryResult 实验室结构化结果,关联三级溯源、发病事件和样本。
type LaboratoryResult struct {
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
TraceRecordID *string `gorm:"column:trace_record_id;type:uuid;index" json:"traceRecordId,omitempty"`
DiseaseEventID *string `gorm:"column:disease_event_id;type:uuid;index" json:"diseaseEventId,omitempty"`
SampleID *string `gorm:"column:sample_id;type:uuid;index" json:"sampleId,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"`
LabName string `gorm:"column:lab_name;size:128" json:"labName"`
ReportNo string `gorm:"column:report_no;size:64" json:"reportNo"`
TestType string `gorm:"column:test_type;size:32" json:"testType"` // molecular_typing/pathogen/environment_sample/other
ResultType string `gorm:"column:result_type;size:16" json:"resultType"`
Pathogen *string `gorm:"size:128" json:"pathogen,omitempty"`
Genotype *string `gorm:"size:128" json:"genotype,omitempty"`
Method *string `gorm:"size:128" json:"method,omitempty"`
SampleNo *string `gorm:"column:sample_no;size:64" json:"sampleNo,omitempty"`
SampleType *string `gorm:"column:sample_type;size:32" json:"sampleType,omitempty"`
Findings *string `gorm:"type:text" json:"findings,omitempty"`
ReportURL *string `gorm:"column:report_url;size:512" json:"reportUrl,omitempty"`
TestedAt *time.Time `gorm:"column:tested_at;type:timestamptz" json:"testedAt,omitempty"`
ConcludedAt *time.Time `gorm:"column:concluded_at;type:timestamptz" json:"concludedAt,omitempty"`
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
}
func (LaboratoryResult) TableName() string { return "laboratory_results" }
// ValidateLaboratoryResult 实验室结果必填项。
func ValidateLaboratoryResult(result LaboratoryResult) error {
if strings.TrimSpace(result.LabName) == "" {
return errors.New("实验室名称不能为空")
}
if strings.TrimSpace(result.ReportNo) == "" {
return errors.New("报告编号不能为空")
}
if !ValidLaboratoryTestType(result.TestType) {
return errors.New("testType 仅支持 molecular_typing/pathogen/environment_sample/other")
}
if !ValidLaboratoryResultType(result.ResultType) {
return errors.New("resultType 仅支持 positive/negative/indeterminate/invalid")
}
return nil
}
// ValidLaboratoryTestType 实验室检测类型。
func ValidLaboratoryTestType(testType string) bool {
switch testType {
case "molecular_typing", "pathogen", "environment_sample", "other":
return true
default:
return false
}
}
// ValidLaboratoryResultType 实验室结果类型。
func ValidLaboratoryResultType(resultType string) bool {
switch resultType {
case "positive", "negative", "indeterminate", "invalid":
return true
default:
return false
}
}